Conversation
Injects a fontSize value into a terminal panel session snapshot via JSON and expects the restored workspace to seed the panel's inheritance font points and carry the value into the next capture. Fails until the terminal snapshot persists per-tab font size. Refs manaflow-ai#8515
SessionTerminalPanelSnapshot gains an optional fontSize field holding the surface's unscaled base font points, mirroring how browser panels persist pageZoom. Capture reads the live surface via cmuxCurrentSurfaceFontSizePoints and normalizes it against the global font magnification, falling back to the lineage-seeded points for hibernated or dead surfaces. Restore threads the value through newTerminalSurface into the surface config template, so a restored tab keeps its own zoom instead of inheriting the pane's. Old snapshots decode with fontSize nil and keep the previous behavior. Fixes manaflow-ai#8515
Bugbot is paused — on-demand spend limit reachedBugbot uses usage-based billing for this team and has hit its on-demand spend limit. A team admin can raise the spend limit in the Cursor dashboard, or wait for the next billing cycle to continue. |
|
@codex review |
|
To use Codex here, create a Codex account and connect to github. |
@Zingzy I can't start this review because your workspace has reached its free monthly review limit. cubic has reviewed 241,631 of the 240,000 allowed lines of code this month. Reviews resume on 1 August 2026 (in 12 days). Paid plans include much higher monthly review limits. Upgrade now to resume reviews. To help optimise your usage, you can tune cubic to get the most out of your usage limits:
|
|
To use Codex here, create a Codex account and connect to github. |
1 similar comment
|
To use Codex here, create a Codex account and connect to github. |
|
✅ Action performedReview finished.
|
📝 WalkthroughWalkthroughTerminal session snapshots now persist optional per-tab font size. Workspace capture records runtime or fallback font points, and session restoration applies persisted values when recreating terminal surfaces. A regression test verifies restoration and subsequent snapshot capture. ChangesTerminal Font Persistence
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant SessionSnapshot
participant Workspace
participant TerminalSurface
SessionSnapshot->>Workspace: restore terminal fontSize
Workspace->>TerminalSurface: create with restoredFontBasePoints
TerminalSurface-->>Workspace: restored terminal surface
Workspace->>SessionSnapshot: capture current fontSize
Suggested reviewers: 🚥 Pre-merge checks | ✅ 25✅ Passed checks (25 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
Greptile SummaryThis PR adds a
Confidence Score: 4/5Safe to merge; the fix is narrowly scoped to persistence serialization and the tab-creation path, and legacy snapshots decode cleanly with nil. The round-trip for explicitly-zoomed tabs works correctly, the test covers both the seeding and re-capture steps, and the existing inheritance dictionary already uses the same normalization formula. The one design gap is that absolute base points are captured for every tab, including unzoomed ones, which prevents a subsequent font-size config change from propagating to already-snapshotted tabs on restart. Sources/Workspace.swift — the capture closure at line 568 unconditionally stores base points for all tabs; worth considering whether nil should be stored when the font size equals the pane's inherited default. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant App as App Quit
participant WS as Workspace.sessionSnapshot
participant Surface as Live Surface
participant Dict as terminalInheritanceFontPointsByPanelId
participant Snap as SessionTerminalPanelSnapshot
App->>WS: sessionSnapshot(includeScrollback:)
WS->>Surface: cmuxCurrentSurfaceFontSizePoints(surface)
alt live surface available
Surface-->>WS: runtimePoints
WS->>WS: baseFontSize(fromRuntimePoints:percent:GlobalFontMagnification.storedPercent)
WS-->>Snap: "fontSize = baseFontBasePoints"
else hibernated / dead surface
WS->>Dict: terminalInheritanceFontPointsByPanelId[panelId]
Dict-->>WS: seededPoints (or nil)
WS-->>Snap: "fontSize = seededPoints"
end
participant Restore as App Restart
participant NTS as newTerminalSurface
participant Seed as seedTerminalInheritanceFontPoints
Restore->>NTS: "restoredFontBasePoints = snapshot.terminal?.fontSize"
NTS->>NTS: "inheritedConfig.fontSize = restoredFontBasePoints"
NTS->>Seed: seedTerminalInheritanceFontPoints(panelId, inheritedConfig)
Seed->>Dict: "terminalInheritanceFontPointsByPanelId[panelId] = fontSize"
NTS->>NTS: TerminalPanel(configTemplate: inheritedConfig, …)
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant App as App Quit
participant WS as Workspace.sessionSnapshot
participant Surface as Live Surface
participant Dict as terminalInheritanceFontPointsByPanelId
participant Snap as SessionTerminalPanelSnapshot
App->>WS: sessionSnapshot(includeScrollback:)
WS->>Surface: cmuxCurrentSurfaceFontSizePoints(surface)
alt live surface available
Surface-->>WS: runtimePoints
WS->>WS: baseFontSize(fromRuntimePoints:percent:GlobalFontMagnification.storedPercent)
WS-->>Snap: "fontSize = baseFontBasePoints"
else hibernated / dead surface
WS->>Dict: terminalInheritanceFontPointsByPanelId[panelId]
Dict-->>WS: seededPoints (or nil)
WS-->>Snap: "fontSize = seededPoints"
end
participant Restore as App Restart
participant NTS as newTerminalSurface
participant Seed as seedTerminalInheritanceFontPoints
Restore->>NTS: "restoredFontBasePoints = snapshot.terminal?.fontSize"
NTS->>NTS: "inheritedConfig.fontSize = restoredFontBasePoints"
NTS->>Seed: seedTerminalInheritanceFontPoints(panelId, inheritedConfig)
Seed->>Dict: "terminalInheritanceFontPointsByPanelId[panelId] = fontSize"
NTS->>NTS: TerminalPanel(configTemplate: inheritedConfig, …)
Reviews (2): Last reviewed commit: "Persist per-tab terminal font zoom acros..." | Re-trigger Greptile |
Greptile SummaryThis PR adds an optional
Confidence Score: 4/5The change is narrowly scoped to session snapshot capture and restore; legacy snapshots with nil fontSize decode without change and fall through to existing behavior, so there is no rollback risk. The capture logic correctly prefers the live C-bridge read and falls back to the inheritance dict only for dead/hibernated surfaces. The restore path overrides inheritedConfig.fontSize before panel creation and the existing seedTerminalInheritanceFontPoints call propagates the value so the round-trip works without a live surface. The one nuance worth watching is the dead-surface fallback: if a user manually zoomed a tab and it was deallocated before rememberTerminalConfigInheritanceSource was refreshed, the seeded value in terminalInheritanceFontPointsByPanelId would lag behind the actual zoom — but this is an acknowledged best-effort fallback, and the live-surface path covers the vast majority of quit-time snapshots. The capturedFontBasePoints closure in Sources/Workspace.swift is the subtlest part of the change and deserves a second read to confirm the magnification-normalization math matches what CmuxSurfaceConfigTemplate.baseFontSize(fromRuntimePoints:percent:) expects. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant W as Workspace
participant SP as SessionPersistence
participant C as C Bridge (cmuxCurrentSurfaceFontSizePoints)
participant D as terminalInheritanceFontPointsByPanelId
Note over W,D: Capture (sessionSnapshot)
W->>C: cmuxCurrentSurfaceFontSizePoints(surface)
alt live surface available
C-->>W: runtimePoints (Float)
W->>W: baseFontSize(fromRuntimePoints:percent:)
W->>SP: "fontSize = basePoints"
else dead / hibernated surface
W->>D: terminalInheritanceFontPointsByPanelId[panelId]
D-->>W: seeded base points (or nil)
W->>SP: "fontSize = seededPoints (or nil)"
end
Note over W,D: Restore (restoreSessionSnapshot → newTerminalSurface)
SP-->>W: snapshot.terminal?.fontSize
alt "fontSize non-nil and > 0"
W->>W: "template.fontSize = restoredFontBasePoints"
W->>W: "inheritedConfig = template"
end
W->>W: TerminalPanel(configTemplate: inheritedConfig)
W->>D: seedTerminalInheritanceFontPoints(panelId, inheritedConfig)
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant W as Workspace
participant SP as SessionPersistence
participant C as C Bridge (cmuxCurrentSurfaceFontSizePoints)
participant D as terminalInheritanceFontPointsByPanelId
Note over W,D: Capture (sessionSnapshot)
W->>C: cmuxCurrentSurfaceFontSizePoints(surface)
alt live surface available
C-->>W: runtimePoints (Float)
W->>W: baseFontSize(fromRuntimePoints:percent:)
W->>SP: "fontSize = basePoints"
else dead / hibernated surface
W->>D: terminalInheritanceFontPointsByPanelId[panelId]
D-->>W: seeded base points (or nil)
W->>SP: "fontSize = seededPoints (or nil)"
end
Note over W,D: Restore (restoreSessionSnapshot → newTerminalSurface)
SP-->>W: snapshot.terminal?.fontSize
alt "fontSize non-nil and > 0"
W->>W: "template.fontSize = restoredFontBasePoints"
W->>W: "inheritedConfig = template"
end
W->>W: TerminalPanel(configTemplate: inheritedConfig)
W->>D: seedTerminalInheritanceFontPoints(panelId, inheritedConfig)
Reviews (3): Last reviewed commit: "Persist per-tab terminal font zoom acros..." | Re-trigger Greptile |
Tabs at the config default no longer write a font size into the session snapshot, so a config font-size change still applies to them on the next restart. Zoom is persisted when the surface reports a runtime adjustment (ghostty_surface_font_size_adjusted) or when it was created from a zoomed template (restored tab, split child of a zoomed pane). The template fallback matters because config-set font sizes never mark the surface as adjusted, so flag-only gating would drop a restored zoom on the second restart.
|
@codex review |
@Zingzy I can't start this review because your workspace has reached its free monthly review limit. cubic has reviewed 241,631 of the 240,000 allowed lines of code this month. Reviews resume on 1 August 2026 (in 12 days). Paid plans include much higher monthly review limits. Upgrade now to resume reviews. To help optimise your usage, you can tune cubic to get the most out of your usage limits:
|
|
To use Codex here, create a Codex account and connect to github. |
|
✅ Action performedReview finished.
|
|
To use Codex here, create a Codex account and connect to github. |
Summary
SessionTerminalPanelSnapshotgains an optionalfontSizefield holding the surface's unscaled base font points, mirroring how browser panels persistpageZoom. Capture reads the live surface viacmuxCurrentSurfaceFontSizePointsand normalizes against the global font magnification, falling back to the lineage-seeded points for hibernated or dead surfaces. Restore threads the value throughnewTerminalSurfaceinto the surface config template, so a restored tab keeps its own zoom instead of inheriting the pane's. Legacy snapshots decode withfontSizenil and keep the previous behavior.Testing
fontSizethrough JSON so it compiles against pre-fix code and fails on behavior rather than on build.xcodebuild test -scheme cmux-unit -only-testing:cmuxTests/SessionPersistenceTests. The new test fails at the seeding assertion on the test-only commit and passes on the fix commit. 133 of 142 suite tests pass; the 9 failing Hermes agent resume tests fail identically on a tree without this change (pre-existing local environment failures, not related).reload.sh --tag font-zoom): zoomed several terminal tabs down and up, quit and relaunched, each tab restored at its own zoom and untouched tabs restored at the default. Split-pane zoom inheritance is unchanged.Demo Video
Review Trigger (Copy/Paste as PR comment)
Checklist
Need help on this PR? Tag
/codesmithwith what you need. Autofix is disabled.Summary by cubic
Persists per-tab terminal font zoom across app restarts so each tab restores its own font size instead of inheriting the pane’s. Only explicitly zoomed tabs persist size; tabs at the config default keep following config after restart. Fixes #8515.
fontSizetoSessionTerminalPanelSnapshotto store unscaled base points; backward compatible when nil.Written for commit 7bba17a. Summary will update on new commits.
Summary by CodeRabbit