Repository navigation
Persist per-tab terminal zoom across restarts #8543
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
24 commits
Select commit
Hold shift + click to select a range
4ad3040
Add failing test for terminal zoom session restore
austinywang 1f6f30d
Persist explicit terminal zoom across session restore
austinywang f62c456
Fix terminal zoom lineage lifecycle edge cases
austinywang 5672f8b
Preserve mutable runtime surface config
austinywang 87733e9
Clear stale terminal zoom inheritance
austinywang 107771c
Make terminal zoom capture allocation-free
austinywang e20e7ab
Preserve terminal zoom ownership during mobile fitting
austinywang 980924b
Merge remote-tracking branch 'origin/main' into issue-8515-font-zoom-…
austinywang 1e52747
Keep unzoomed restores on current terminal config
austinywang 781ef04
Keep terminal zoom inheritance source coherent
austinywang 96b4123
test: reject unmounted terminal zoom sources
austinywang 66fd1be
fix: record terminal zoom source after insertion
austinywang e2086cc
Merge remote-tracking branch 'origin/main' into issue-8515-font-zoom-…
austinywang a1d3134
Move terminal font creation policy into core
austinywang 08eef76
test: preserve initial terminal font template
austinywang 11eb1c8
Preserve terminal font size on first runtime creation
austinywang d6c2e46
test: cover font ownership and crash pruning
austinywang 5af3691
Preserve explicit terminal font ownership
austinywang a9baff1
test: cover font bounds and live lineage cache
austinywang a1b2482
fix: bound font persistence and refresh lineage cache
austinywang d604ea1
test: preserve terminal runtime default sentinel
austinywang 39ddc62
fix: preserve terminal runtime default sentinel
austinywang fe081b4
Merge origin/main into issue-8515-font-zoom-persistence
austinywang 425ff2c
Merge origin/main into issue-8515-font-zoom-persistence
austinywang File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
14 changes: 14 additions & 0 deletions
14
Packages/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/MobileViewportFontFitState.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| /// Temporary runtime font state owned by mobile viewport fitting. | ||
| struct MobileViewportFontFitState: Equatable { | ||
| var baseRuntimePointSize: Float32 | ||
| var fittedRuntimePointSize: Float32 | ||
|
|
||
| func matchesFittedRuntimePointSize(_ runtimePointSize: Float32) -> Bool { | ||
| abs(runtimePointSize - fittedRuntimePointSize) <= 0.05 | ||
| } | ||
|
|
||
| mutating func rebase(to runtimePointSize: Float32) { | ||
| baseRuntimePointSize = runtimePointSize | ||
| fittedRuntimePointSize = runtimePointSize | ||
| } | ||
| } |
108 changes: 108 additions & 0 deletions
108
...ges/macOS/CmuxTerminal/Sources/CmuxTerminal/Surface/TerminalSurface+FontSizeLineage.swift
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,108 @@ | ||
| public import CmuxTerminalCore | ||
| internal import GhosttyKit | ||
|
|
||
| extension TerminalSurface { | ||
| /// Captures the current font size and its surface-local ownership state. | ||
| /// | ||
| /// Live Ghostty state is authoritative. When the runtime is unavailable, | ||
| /// the last captured lineage survives hibernation and session restoration. | ||
| /// | ||
| /// - Returns: Current font-size lineage, or nil before a size is known. | ||
| @MainActor | ||
| public func fontSizeLineageSnapshot() -> TerminalFontSizeLineage? { | ||
| guard let runtimeSurface = liveSurfaceForGhosttyAccess( | ||
| reason: "fontSizeLineage.snapshot" | ||
| ) else { | ||
| return lastKnownFontSizeLineage | ||
| } | ||
| guard let runtimePoints = GhosttySurfaceRuntimeProbe.currentSurfaceFontSizePoints( | ||
| runtimeSurface | ||
| ) else { | ||
| return lastKnownFontSizeLineage | ||
| } | ||
|
|
||
| return recordObservedFontSizeLineage( | ||
| runtimePoints: runtimePoints, | ||
| isExplicitOverride: ghostty_surface_font_size_adjusted(runtimeSurface), | ||
| globalFontMagnificationPercent: globalFontMagnificationPercent() | ||
| ) | ||
| } | ||
|
|
||
| /// Reconciles observed runtime points with durable surface ownership. | ||
| /// | ||
| /// A live value matching the active mobile fit is temporary and leaves the | ||
| /// pre-fit lineage unchanged. A different live value came from outside the | ||
| /// fitter, so it becomes the new durable base and restore point. | ||
| @MainActor | ||
| func recordObservedFontSizeLineage( | ||
| runtimePoints: Float32, | ||
| isExplicitOverride: Bool, | ||
| globalFontMagnificationPercent: Int | ||
| ) -> TerminalFontSizeLineage? { | ||
| guard runtimePoints.isFinite, runtimePoints > 0 else { | ||
| return lastKnownFontSizeLineage | ||
| } | ||
| if var fitState = mobileViewportFontFitState { | ||
| guard !isExplicitOverride | ||
| || !fitState.matchesFittedRuntimePointSize(runtimePoints) else { | ||
| return lastKnownFontSizeLineage | ||
| } | ||
| fitState.rebase(to: runtimePoints) | ||
| mobileViewportFontFitState = fitState | ||
| } | ||
|
|
||
| let lineage = TerminalFontSizeLineage( | ||
| basePoints: CmuxSurfaceConfigTemplate.baseFontSize( | ||
| fromRuntimePoints: runtimePoints, | ||
| percent: globalFontMagnificationPercent | ||
| ), | ||
| isExplicitOverride: isExplicitOverride | ||
| ) | ||
| recordCurrentFontSizeLineage(lineage) | ||
| return lineage | ||
| } | ||
|
|
||
| /// Records live font-size lineage for hibernation and split inheritance. | ||
| /// | ||
| /// A non-explicit value is retained as the last known split-inheritance | ||
| /// value, while separately recording that this surface must follow current | ||
| /// config when its own runtime is recreated. | ||
| @MainActor | ||
| func recordCurrentFontSizeLineage(_ lineage: TerminalFontSizeLineage) { | ||
| guard lastKnownFontSizeLineage != lineage else { return } | ||
| lastKnownFontSizeLineage = lineage | ||
| onFontSizeLineageChanged?(lineage) | ||
| } | ||
|
|
||
| /// Resolves the Swift-owned template used to create this surface's runtime. | ||
| /// | ||
| /// Initial non-explicit lineage seeds the first native runtime. After a | ||
| /// native lifetime, non-explicit lineage remains available to descendants | ||
| /// but must not seed this surface again because Cmd+0 and ordinary unzoomed | ||
| /// terminals follow the then-current terminal config. | ||
| @MainActor | ||
| func runtimeCreationConfigTemplate() -> CmuxSurfaceConfigTemplate { | ||
| var template = configTemplate ?? CmuxSurfaceConfigTemplate() | ||
| if lastKnownFontSizeLineage?.isExplicitOverride == false, | ||
| runtimeSurfaceGeneration > 0 { | ||
| template.fontSizeLineage = nil | ||
| } else if let lastKnownFontSizeLineage { | ||
| template.fontSizeLineage = lastKnownFontSizeLineage | ||
| } | ||
| return template | ||
| } | ||
|
|
||
| /// Returns the explicit unscaled font override to persist in a session snapshot. | ||
| /// | ||
| /// Nil means the terminal follows the current config and should not pin a | ||
| /// font size across relaunches. | ||
| @MainActor | ||
| public func sessionFontSizeOverrideBasePoints() -> Float32? { | ||
| guard let lineage = fontSizeLineageSnapshot(), | ||
| lineage.isExplicitOverride, | ||
| TerminalFontSizePolicy().acceptsPersistedBasePoints(lineage.basePoints) else { | ||
| return nil | ||
| } | ||
| return lineage.basePoints | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.