Add sidebar-font-size Ghostty config option (closes #2643)#2990
Add sidebar-font-size Ghostty config option (closes #2643)#2990livermush wants to merge 14 commits into
Conversation
Adds a configurable sidebar font size (10-20pt, default 12.5) via the Ghostty config key `sidebar-font-size`. All other sidebar text (close buttons, metadata rows, progress labels, PR/remote/branch info, log entries, markdown blocks) scales proportionally from this primary size, preserving the existing visual hierarchy. Scope: TabItemView and its sub-views (SidebarWorkspaceDescriptionText, SidebarMetadataRows, SidebarMetadataEntryRow, SidebarMetadataMarkdownBlocks, SidebarMetadataMarkdownBlockRow, PullRequestStatusIcon). Other sidebar chrome (feedback composer, help menu, dev footer) out of scope for this change. The scale is exposed on SidebarTabItemSettingsSnapshot (already Equatable and observed by TabItemView) so the typing-latency contract around TabItemView equatable snapshotting is preserved — no new @ObservedObject or body-time lookups in the hot path. Refs manaflow-ai#2643 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds SidebarFontSizeConfigTests matching the SidebarBackgroundConfigTests pattern: verify default, valid parse, fractional parse, min/max clamp, and non-numeric fallback to default. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…ctable
Adds:
- GhosttyConfigTests: trailing-zero parse (14.0 == 14), injected-loader
round-trip through GhosttyConfig.load(loadFromDisk:), and later-path-
wins semantics (the contract that ~/Library/App Support overrides
~/.config/ghostty when both are present).
- SidebarTabItemSettingsSnapshotFontScaleTests: unit scale at default,
proportional scaling at 18pt (→ 1.44), clamp-up below min, clamp-down
above max, Equatable-flips-on-scale-diff (protects the
TabItemView.equatable() re-render contract), Equatable-holds-on-match.
Refactor to support the snapshot tests:
- SidebarTabItemSettingsSnapshot is promoted from private to internal so
`@testable import cmux_DEV` can see it. The store and view both live
in the same file, so no external API is newly exposed — only tests.
- init now takes an injectable `sidebarFontSizeProvider: () -> CGFloat`
defaulting to `{ GhosttyConfig.load().sidebarFontSize }`. Production
behavior is unchanged; tests pass a constant closure to avoid touching
the real config file.
All 15 new tests pass locally via
`xcodebuild test-without-building -scheme cmux-unit \
-only-testing:cmuxTests/SidebarFontSizeConfigTests \
-only-testing:cmuxTests/SidebarTabItemSettingsSnapshotFontScaleTests`.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Someone is attempting to deploy a commit to the Manaflow Team on Vercel. A member of the Team first needs to authorize it. |
📝 WalkthroughWalkthroughAdds a new Ghostty config key ChangesSidebar font scaling + wiring
Tests
Sequence Diagram(s)sequenceDiagram
participant User
participant ConfigLoader
participant GhosttyConfig
participant SidebarTabItemSettingsStore
participant TabItemView
participant SidebarSubViews
User->>ConfigLoader: edit config (sidebar-font-size)
ConfigLoader->>GhosttyConfig: parse(new config)
GhosttyConfig-->>SidebarTabItemSettingsStore: post .ghosttyConfigDidReload
SidebarTabItemSettingsStore->>SidebarTabItemSettingsStore: compute SidebarTabItemSettingsSnapshot (sidebarFontScale)
SidebarTabItemSettingsStore-->>TabItemView: publish updated settings
TabItemView->>SidebarSubViews: pass fontScale -> render scaled fonts/icons/layout
Estimated code review effort🎯 4 (Complex) | ⏱️ ~40 minutes Possibly related PRs
Poem
Caution Pre-merge checks failedPlease resolve all errors before merging. Addressing warnings is optional.
❌ Failed checks (1 error, 1 warning)
✅ Passed checks (15 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: 5/5Safe to merge — the change is additive, follows the existing font-size config pattern throughout, and all affected paths have test coverage. The config parsing, snapshot derivation, live-reload wiring, and view-hierarchy propagation are all correct. Cache invalidation happens before the reload notification is posted, so the snapshot always reads fresh config. The Equatable path is synthesized and correctly includes sidebarFontScale, ensuring TabItemView re-renders on config change. No new blocking synchronization, actor isolation mistakes, or user-facing strings requiring localization were introduced. No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant Config as GhosttyConfig
participant Store as SidebarTabItemSettingsStore
participant Snapshot as SidebarTabItemSettingsSnapshot
participant View as TabItemView
Note over Config: User edits sidebar-font-size
Config->>Config: invalidateLoadCache()
Config->>Store: post(.ghosttyConfigDidReload)
Store->>Store: ghosttyConfigObserver fires (queue: .main)
Store->>Snapshot: init(sidebarFontSizeProvider)
Snapshot->>Config: GhosttyConfig.load() cache miss
Config-->>Snapshot: sidebarFontSize clamped 10-20
Snapshot->>Snapshot: "sidebarFontScale = clamped / 12.5"
Snapshot-->>Store: new snapshot
Store->>View: "@Published triggers re-eval"
Note over View: Synthesized Equatable includes sidebarFontScale
View->>View: "Apply N * fontScale to all font sizes"
Reviews (7): Last reviewed commit: "Merge origin/main into sidebar-font-scal..." | Re-trigger Greptile |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
Sources/ContentView.swift (2)
14247-14340:⚠️ Potential issue | 🟡 MinorScale the custom PR icons with the row text.
fontScaleonly reaches the closed SF Symbol; the custom open/merged icons keep fixed geometry, and the closed icon still uses a fixed frame. This makes PR rows inconsistent at non-default sidebar font sizes.Proposed direction
private struct PullRequestStatusIcon: View { let status: SidebarPullRequestStatus let color: Color var fontScale: CGFloat = 1 - private static let frameSize: CGFloat = 12 + private var frameSize: CGFloat { 13 * fontScale } var body: some View { switch status { case .open: - PullRequestOpenIcon(color: color) + PullRequestOpenIcon(color: color, fontScale: fontScale) case .merged: - PullRequestMergedIcon(color: color) + PullRequestMergedIcon(color: color, fontScale: fontScale) case .closed: Image(systemName: "xmark.circle") .font(.system(size: 7 * fontScale, weight: .regular)) .foregroundColor(color) - .frame(width: Self.frameSize, height: Self.frameSize) + .frame(width: frameSize, height: frameSize) } } } private struct PullRequestOpenIcon: View { let color: Color - private static let stroke = StrokeStyle(lineWidth: 1.2, lineCap: .round, lineJoin: .round) - private static let nodeDiameter: CGFloat = 3.0 - private static let frameSize: CGFloat = 13 + var fontScale: CGFloat = 1 + private var stroke: StrokeStyle { + StrokeStyle(lineWidth: 1.2 * fontScale, lineCap: .round, lineJoin: .round) + } + private var nodeDiameter: CGFloat { 3.0 * fontScale } + private var frameSize: CGFloat { 13 * fontScale } var body: some View { ZStack { Path { path in - path.move(to: CGPoint(x: 3.0, y: 4.8)) + path.move(to: CGPoint(x: 3.0 * fontScale, y: 4.8 * fontScale)) // scale the remaining path coordinates the same way } - .stroke(color, style: Self.stroke) + .stroke(color, style: stroke) // scale node frames/positions similarly } - .frame(width: Self.frameSize, height: Self.frameSize) + .frame(width: frameSize, height: frameSize) } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Sources/ContentView.swift` around lines 14247 - 14340, The custom PR icons (PullRequestOpenIcon, PullRequestMergedIcon) and the closed Image use fixed geometry so they don't scale with sidebar font size; update PullRequestStatusIcon to pass the fontScale down and change PullRequestOpenIcon and PullRequestMergedIcon to accept a fontScale: CGFloat (default 1) and multiply their static dimensions (frameSize, nodeDiameter, positions, StrokeStyle.lineWidth) by fontScale (or compute scaled constants) so the Path coordinates, Circle positions, and .frame sizes scale, and change the closed-case Image to use .frame(width: Self.frameSize * fontScale, height: Self.frameSize * fontScale) and .font(.system(size: 7 * fontScale, ...)) so all three branches (PullRequestOpenIcon, PullRequestMergedIcon, and closed Image) scale consistently with the fontScale passed from PullRequestStatusIcon.
13151-13152:⚠️ Potential issue | 🟡 MinorScale the workspace shortcut hint too.
The shortcut pill still uses a fixed
10ptfont, sosidebar-font-sizewon’t affect this sidebar text.Proposed fix
- ShortcutHintPill(text: workspaceShortcutLabel, fontSize: 10, emphasis: shortcutHintEmphasis) + ShortcutHintPill(text: workspaceShortcutLabel, fontSize: 10 * fontScale, emphasis: shortcutHintEmphasis)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Sources/ContentView.swift` around lines 13151 - 13152, The ShortcutHintPill currently hardcodes fontSize: 10 which prevents it from honoring the sidebar font size setting; update the call in the showsWorkspaceShortcutHint / workspaceShortcutLabel block to pass the dynamic sidebar font size used elsewhere (e.g., replace the literal 10 with the same variable/property that other sidebar text uses, such as sidebarFontSize or the shared fontSize binding) so ShortcutHintPill(text: workspaceShortcutLabel, fontSize: <sidebarFontSize>, emphasis: shortcutHintEmphasis) scales with the sidebar-font-size setting.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Sources/GhosttyConfig.swift`:
- Around line 258-265: The parsing for "sidebar-font-size" in GhosttyConfig
allows NaN/infinite values to slip through; before clamping and assigning to
sidebarFontSize, validate the parsed Double (e.g. the local size variable) by
rejecting non-finite or NaN values (use size.isFinite or !size.isNaN) and only
perform the min/max clamp when the value is finite; otherwise fall back to
leaving sidebarFontSize unchanged (or the existing invalid-value behavior).
---
Outside diff comments:
In `@Sources/ContentView.swift`:
- Around line 14247-14340: The custom PR icons (PullRequestOpenIcon,
PullRequestMergedIcon) and the closed Image use fixed geometry so they don't
scale with sidebar font size; update PullRequestStatusIcon to pass the fontScale
down and change PullRequestOpenIcon and PullRequestMergedIcon to accept a
fontScale: CGFloat (default 1) and multiply their static dimensions (frameSize,
nodeDiameter, positions, StrokeStyle.lineWidth) by fontScale (or compute scaled
constants) so the Path coordinates, Circle positions, and .frame sizes scale,
and change the closed-case Image to use .frame(width: Self.frameSize *
fontScale, height: Self.frameSize * fontScale) and .font(.system(size: 7 *
fontScale, ...)) so all three branches (PullRequestOpenIcon,
PullRequestMergedIcon, and closed Image) scale consistently with the fontScale
passed from PullRequestStatusIcon.
- Around line 13151-13152: The ShortcutHintPill currently hardcodes fontSize: 10
which prevents it from honoring the sidebar font size setting; update the call
in the showsWorkspaceShortcutHint / workspaceShortcutLabel block to pass the
dynamic sidebar font size used elsewhere (e.g., replace the literal 10 with the
same variable/property that other sidebar text uses, such as sidebarFontSize or
the shared fontSize binding) so ShortcutHintPill(text: workspaceShortcutLabel,
fontSize: <sidebarFontSize>, emphasis: shortcutHintEmphasis) scales with the
sidebar-font-size setting.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 2ad5f50c-8027-4fb4-9999-7ca7090b811e
📒 Files selected for processing (4)
Sources/ContentView.swiftSources/GhosttyConfig.swiftcmuxTests/GhosttyConfigTests.swiftcmuxTests/SidebarOrderingTests.swift
Three fixes from CodeRabbit's review on PR manaflow-ai#2990: 1. NaN/infinity poisoning the clamp. `Double("nan")` and `Double("inf")` are valid per IEEE 754 / Apple docs; `min/max` on NaN yields NaN, which would have made `sidebarFontScale` NaN → every `N * scale` NaN → SwiftUI renders nothing → invisible sidebar. Added `size.isFinite` guard and three regression tests: `nan`, `inf`, `-infinity`. 2. PR row icons didn't scale. `PullRequestOpenIcon` and `PullRequestMergedIcon` are hand-drawn with hardcoded `Path` geometry, stroke widths, and node positions. Rather than thread `fontScale` through every coordinate (CodeRabbit's proposed diff touches ~20 literals, fragile for pixel-grid snapping), apply a single `.scaleEffect(fontScale)` with a proportionally-sized frame. Behaviorally identical at scale=1, and SwiftUI handles the stroke/path/frame transform together. Also scaled the closed-state `xmark.circle` frame so all three branches grow together. 3. Workspace shortcut hint pill. The `ShortcutHintPill` call in the sidebar trailing accessory hardcoded `fontSize: 10`; now uses `10 * fontScale`. All 18 tests still pass locally. Debug build (`reload.sh --tag sidebar-font-scale`) compiles clean. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
Sources/ContentView.swift (1)
13107-13161:⚠️ Potential issue | 🟡 MinorScale the fixed accessory containers with the fonts.
The unread badge, close button, and accessory slot still use fixed 16pt frames while their glyphs now scale. At larger sidebar font sizes, counts/icons can clip or overlap.
Proposed adjustment
let pullRequestRows: [PullRequestDisplay] = { guard detailVisibility.showsPullRequests, let orderedPanelIds else { return [] } return pullRequestDisplays(orderedPanelIds: orderedPanelIds) }() + let scaledAccessorySize = max(16, 16 * fontScale) + let scaledTrailingAccessoryWidth = max(trailingAccessoryWidth, scaledAccessorySize) VStack(alignment: .leading, spacing: 4) { HStack(spacing: 8) { if unreadCount > 0 { ZStack { Circle() .fill(activeUnreadBadgeFillColor) Text("\(unreadCount)") .font(.system(size: 9 * fontScale, weight: .semibold)) .foregroundColor(.white) } - .frame(width: 16, height: 16) + .frame(width: scaledAccessorySize, height: scaledAccessorySize) } @@ .buttonStyle(.plain) .safeHelp(closeButtonTooltip) - .frame(width: SidebarTrailingAccessoryWidthPolicy.closeButtonWidth, height: 16, alignment: .center) + .frame(width: scaledAccessorySize, height: scaledAccessorySize, alignment: .center) .opacity(showCloseButton && !showsWorkspaceShortcutHint ? 1 : 0) .allowsHitTesting(showCloseButton && !showsWorkspaceShortcutHint) @@ .animation(.easeOut(duration: 0.12), value: showsModifierShortcutHints || alwaysShowShortcutHints) - .frame(width: trailingAccessoryWidth, height: 16, alignment: .trailing) + .frame(width: scaledTrailingAccessoryWidth, height: scaledAccessorySize, alignment: .trailing) }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@Sources/ContentView.swift` around lines 13107 - 13161, The fixed 16pt accessory frames cause clipping when fonts scale; update the badge, close-button and trailing accessory container to scale with fontScale (e.g., replace hard-coded width/height: 16 with a computed size derived from fontScale or the glyph font sizes). Modify the Circle badge frame, the close button .frame(...) and the outer .frame(width: trailingAccessoryWidth, height: 16, ...) so their height/width use a scaled value (e.g., badgeSize = 16 * fontScale or compute from the font sizes used for the glyphs) and ensure SidebarTrailingAccessoryWidthPolicy.closeButtonWidth usage is updated or wrapped to respect the scaled dimensions; keep alignment and hit-testing logic the same.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Outside diff comments:
In `@Sources/ContentView.swift`:
- Around line 13107-13161: The fixed 16pt accessory frames cause clipping when
fonts scale; update the badge, close-button and trailing accessory container to
scale with fontScale (e.g., replace hard-coded width/height: 16 with a computed
size derived from fontScale or the glyph font sizes). Modify the Circle badge
frame, the close button .frame(...) and the outer .frame(width:
trailingAccessoryWidth, height: 16, ...) so their height/width use a scaled
value (e.g., badgeSize = 16 * fontScale or compute from the font sizes used for
the glyphs) and ensure SidebarTrailingAccessoryWidthPolicy.closeButtonWidth
usage is updated or wrapped to respect the scaled dimensions; keep alignment and
hit-testing logic the same.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b9e352dc-dfb2-44f0-9ed6-2f6ac8e994e8
📒 Files selected for processing (3)
Sources/ContentView.swiftSources/GhosttyConfig.swiftcmuxTests/GhosttyConfigTests.swift
🚧 Files skipped from review as they are similar to previous changes (1)
- Sources/GhosttyConfig.swift
Addresses CodeRabbit finding on manaflow-ai#2990: the unread badge, close button, and trailing accessory container kept hardcoded 16pt frames while their inner glyphs were already scaling with fontScale, so at sidebar-font-size above ~12.5pt the glyphs risked clipping or overlapping. Introduce `scaledAccessorySize = max(16, 16 * fontScale)` so the floor at scale <= 1 preserves the existing hit-target size (no-op for default and smaller fonts), and only grows when the user bumps the sidebar font. Apply it to the badge circle, close-button frame, and outer trailing accessory frame. Width of the trailing container uses `max(trailingAccessoryWidth, scaledAccessorySize)` so the shortcut-hint pill path keeps its prior layout when fontScale is 1. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Resolves conflicts in Sources/ContentView.swift where origin/main moved sidebar row precomputations into `workspaceSnapshot` and renamed `tab.title` → `workspaceSnapshot.title`. Kept the snapshot-sourced values and re-applied `* fontScale` multipliers added for sidebar-font-size, plus the `scaledAccessorySize` / `scaledTrailingAccessoryWidth` helpers. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@Sources/ContentView.swift`:
- Around line 12029-12035: The change forces a minimum 16pt trailing gutter even
when there's no trailing accessory; update the calculation so
scaledTrailingAccessoryWidth only applies the 16pt floor when a trailing
accessory exists. In other words, use the existing trailingAccessoryWidth as-is
when it's 0, otherwise compute scaledAccessorySize (max(16, 16 * fontScale)) and
set scaledTrailingAccessoryWidth to the greater of trailingAccessoryWidth and
scaledAccessorySize; reference scaledAccessorySize,
scaledTrailingAccessoryWidth, trailingAccessoryWidth and fontScale when making
the change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c72717be-f348-45ab-82cf-96d384859176
📒 Files selected for processing (3)
Sources/ContentView.swiftSources/GhosttyConfig.swiftcmuxTests/GhosttyConfigTests.swift
🚧 Files skipped from review as they are similar to previous changes (2)
- cmuxTests/GhosttyConfigTests.swift
- Sources/GhosttyConfig.swift
CodeRabbit review on manaflow-ai#2990: the merge resolution applied max(16, 16 * fontScale) unconditionally to scaledTrailingAccessoryWidth, which forces a 16pt gutter on rows where trailingAccessoryWidth was 0 (no close button AND no shortcut pill). That steals title space from single- workspace rows that previously had a zero-width trailing gutter. Keep the 16pt floor only when a trailing accessory is actually shown. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
+1, this would let me actually use cmux at my screen scale!! Thanks for your hard work! |
Resolves four conflict regions in Sources/ContentView.swift: 1. SidebarTabItemSettingsSnapshot: keep both new fields (sidebarFontScale + iMessageModeEnabled), and adopt main's simpler shortcut-hint defaults — main removed the sidebarHintXKey/sidebarHintYKey/alwaysShowHintsKey UserDefaults plumbing, so HEAD's Self.double(...) calls no longer compile. 2. End-of-init: union both new assignments. 3. Trailing accessory frame: combine main's new .shortcutHintVisibilityAnimation modifier with HEAD's font-scaled frame width/size. 4. Sidebar PR row: keep main's clickability toggle / localized tooltip / accessibility-id structure, while threading `fontScale` through PullRequestStatusIcon and the row font. Drop now-unused `private static func double` helper. Take main's newer ghostty (22fa801f) and vendor/bonsplit (f65eccb) submodule pointers — this branch made no intentional submodule changes. Verified the Swift compile succeeds locally (ContentView.o produced); the build only fails at the Zig Run Script phase due to a Zig 0.15.2 vs 0.16 local environment mismatch unrelated to this merge. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
@coderabbitai resume Merged origin/main into the branch (resolved conflicts in |
|
✅ Actions performedReviews resumed. Review triggered.
|
|
@austinywang @lawrencecchen — when either of you has a moment, this is ready for a maintainer pass. The branch is now caught up with |
|
Would love to see this merged 🙏 |
# Conflicts: # Sources/ContentView.swift
|
Adding another +1 to this... my poor eyes are straining hard to read the sidebar text. 🙏 |
|
+1. The font is so small! |
# Conflicts: # Sources/ContentView.swift
|
Just rebased — conflict with Bumping in case this is on anyone's radar: this PR has 6 +1s, the linked issue #2643 has 8 +1s (most recent yesterday), and CodeRabbit approved on May 9. Would appreciate a human review whenever someone has a cycle. |
Restore internal visibility so cmuxTests can `@testable import` the struct. Commit bc27aed ("test(sidebar): expand sidebar-font-size coverage + make snapshot injectable") originally relaxed this from `private` to internal, but the access modifier was reverted somewhere in the merge history. That broke compilation of the existing 6 SidebarTabItemSettingsSnapshotFontScaleTests tests in cmuxTests/SidebarOrderingTests.swift with `cannot find 'SidebarTabItemSettingsSnapshot' in scope`. The init's `sidebarFontSizeProvider` parameter is intact; only the access modifier needed restoring. With this fix all 18 feature tests pass (12 SidebarFontSizeConfigTests + 6 snapshot scale tests). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Local test results (macOS 26.5 / Xcode 26.5)Built and ran Feature coverageAll 18 sidebar-font-size tests pass on the PR:
Suite totals
Failure delta
About commit
|
|
Thanks for doing this -- ++ on the need for this (eyesight). great addition |
Resolved conflict in Sources/ContentView.swift: main consolidated the workspace-row shortcut-hint pill into the shared sidebarShortcutHintOverlay modifier (replacing the old inline .topTrailing pill with EmptyView). Adopted main's structure and threaded fontScale through sidebarShortcutHintOverlay (default 1.0) so the hint pill still scales with sidebar-font-size while keeping a single pill render path. Submodule pointers (ghostty, vendor/bonsplit) match main. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Rebased onto latest The only thing blocking merge is CI gating: the four required checks ( Could a maintainer hit "Approve and run workflows" in the Checks section? Required approving reviews on |
|
+1, this is exactly the gap I hit. I run many parallel Claude Code / Codex sessions and the sidebar tab text is too small to scan across tabs, with no way to size it today — |
|
Closing this — the feature shipped via #4798, which landed sidebar (and surface-tab-bar) font sizing with a Settings slider, CLI support, and docs, and closed #2643 as completed. Thanks to @austinywang for getting it across the line, and to everyone who +1'd here. 🎉 For anyone arriving from the issue: set it in |
Summary
sidebar-font-sizeGhostty config key (default 12.5, clamped 10–20) to scale sidebar workspace tab labels and all proportional sidebar chrome.scale = sidebarFontSize / 12.5, preserving the existing visual hierarchy.SidebarTabItemSettingsSnapshot(alreadyEquatableand observed byTabItemView) so the typing-latency contract onTabItemViewis preserved — no new@ObservedObjector body-time lookups on the hot path.Closes #2643.
Approach
Mirrors the existing
font-size/surface-tab-bar-font-sizepattern:GhosttyConfiggainssidebarFontSize: CGFloatwithdefault=12.5,min=10,max=20, and a parser case forsidebar-font-size.SidebarTabItemSettingsSnapshotcomputessidebarFontScale = sidebarFontSize / defaultSidebarFontSizeand refreshes on.ghosttyConfigDidReload. TheEquatableconformance already covers the new property via the full-snapshot equality check, so no existing callers need changes..font(.system(size: N, ...))inside the sidebar tree was replaced withN * fontScalewherefontScaleis read from the pre-computed snapshot. Scope limited toTabItemViewand its nested views.Scope
In scope (all in
Sources/ContentView.swift):TabItemView— title, unread dot, pin, close, subtitle, log icon + text, progress label, branch row, ports, PR status, remotePullRequestStatusIconSidebarWorkspaceDescriptionTextSidebarMetadataRows+SidebarMetadataEntryRowSidebarMetadataMarkdownBlocks+SidebarMetadataMarkdownBlockRowIntentionally out of scope (can be follow-ups):
SidebarFeedbackComposerSheet,SidebarHelpMenuButton,SidebarDevFooterUsage
Then either restart cmux or run
cmux reload-config— running windows pick the new size up via the existing.ghosttyConfigDidReloadpath.Values outside 10–20 are clamped. Missing / non-numeric values fall back to the 12.5 default.
Test plan
xcodebuild -scheme cmux-unit build-for-testing— compiles clean./scripts/reload.sh --tag sidebar-font-scale— Debug build succeedsSidebarFontSizeConfigTests(default, valid parse, fractional, min+max clamp, non-numeric fallback)sidebar-font-size = 10— sidebar renders at min, no text clippingsidebar-font-size = 12.5— no visual diff vs. mainsidebar-font-size = 15— sidebar text scales up, layout balancedsidebar-font-size = 20— sidebar renders at max, row heights expand without overlapcmux reload-config— open windows pick up new valueNotes for reviewers
TabItemViewis latency-sensitive (perCLAUDE.md: "do not add@EnvironmentObject,@ObservedObject(besidestab), or@Bindingproperties without updating the==function"). The scale is folded into the existingSidebarTabItemSettingsSnapshot— alreadyEquatable, already covered by==, already listened to via a singleNotificationCenterobserver inSidebarTabItemSettingsStore. No new observers on the hot path.scaleis aCGFloatmultiplication at the call site — no per-frame allocation, no per-frame lookup.CLAUDE.md's two-commit policy).Summary by cubic
Adds a
sidebar-font-sizeGhostty config to scale all sidebar text and chrome (10–20 pt, default 12.5) with live reload. Closes #2643.New Features
sidebar-font-size(clamped) and derivessidebarFontScaleonSidebarTabItemSettingsSnapshot; store refreshes on.ghosttyConfigDidReload.TabItemViewand subviews (titles/subtitles, directory text, metadata rows/markdown blocks, remote/branch/ports, logs, PR rows/icons via transform, shortcut hint pill via the shared overlay) while preserving theEquatablesnapshot path.Bug Fixes
nan,inf) during parse to prevent NaN scales.fontScale(16 pt min) to avoid clipping.Written for commit 0241ddd. Summary will update on new commits.
Summary by CodeRabbit