Repository navigation
Conversation
Adds a new bool config option that, when enabled, automatically equalizes all splits in the current window whenever a split is created or closed. Defaults to false to preserve existing behavior. This is the public-facing knob; the actual equalization is performed by the apprt layer (macOS, GTK) which owns the split tree, in follow-up commits. Refs: #3861, #11040
When auto-equalize-splits is enabled, the macOS terminal controller runs SplitTree.equalized() on the new tree right before publishing it to the controller, both when adding a new split and when removing one. Equalization happens on a value-typed copy of the tree before replaceSurfaceTree commits it, so it's invisible to listeners and keeps undo/redo intact. No use-after-free risk: the surface tree is owned by the controller and is rewritten on the main queue, far away from the closing-action guard in src/Surface.zig that tripped up chained keybinds. Refs: #3861, #11040
GTK split-tree mirrors the macOS behavior: when the user enables auto-equalize-splits the new tree is equalized in place before setTree publishes it, both in newSplit and in the surface-removal path. A small autoEqualize helper centralizes the config check and the deinit/replace dance, and is a no-op when the option is off. Refs: #3861
Contributor
|
Hi @orbanconsult, thanks for your interest in contributing! This project requires that pull request authors are vouched, and you are not in the list of vouched users. This PR will be closed automatically. See https://github.com/ghostty-org/ghostty/blob/main/CONTRIBUTING.md for more details. |
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Adds a new bool config option
auto-equalize-splits(defaultfalse)that, when enabled, automatically equalizes all splits in the current
window whenever a split is created or closed. Equivalent to invoking
equalize_splitsimmediately after every create/close, but unlike achained keybind it works across
close_surfacetoo.Closes #3861.
Motivation
Issue #3861 asks for iTerm2-style auto-equalize on every split. Today
the only way to get this is to chain
equalize_splitsafter everysplit-creating keybind (works fine post #10015), and there is no
way to do it after
close_surface: chained keybinds containing aclosing action exit the chain immediately because the
Surfaceselfpointer is freed (see
src/Surface.zigclosingActionguard, andthe discussion with @jcollie in #11040).
Rather than reaching across the apprt boundary from inside the
freed-Surface code path, this PR plumbs a single config flag down to
the runtime layer that already owns the split tree, and equalizes
in place there - on macOS in
BaseTerminalController, on GTK inSplitTree. No use-after-free, no chain-machinery changes, no newactions.
Approach
src/config/Config.zig: new@\"auto-equalize-splits\": bool = falsefield with doc comment. Auto-wired by the existing reflective config
parser, so CLI flag and
+show-config --default --docspick it upfor free.
Ghostty.Config.swift,BaseTerminalController.swift):add accessor and
DerivedConfigfield. When the flag is true,newSplit()andremoveSurfaceNode()passtree.equalized()(instead of the raw inserted/removed tree) to
replaceSurfaceTree.Because equalization runs on a value-typed copy before publishing,
it's invisible to listeners and undo/redo restores exactly the
pre-operation tree.
src/apprt/gtk/class/split_tree.zig): newautoEqualizehelper centralizes the config check and the equalize/deinit/replace
dance. Called from
newSplitand the surface-removal path rightbefore
setTree.Behavior change
Default: zero behavior change. Off by default.
With
auto-equalize-splits = true:that window so all leaves are weighted equally (same algorithm as
the existing
equalize_splitsaction / divider double-click).subsequent create/close. This is documented in the doc comment;
it matches the user-requested 'always equalize' semantics and is
consistent with how the existing
equalize_splitsaction behaves.Tests performed
zig build -Demit-macos-app=falseclean on the latest tip ofmain.macos/build.nu --configuration ReleaseLocal --action buildcleanon Xcode 26.4 + macOS Tahoe 26.4.1 arm64 with Zig 0.15.2 (Homebrew
zig@0.15, contains the patch noted in HACKING.md for the Xcode26.4 linking bug).
zig build test -Dtest-filter=Configand-Dtest-filter=splitclean.+show-config --defaultshowsauto-equalize-splits = false;--docsrenders the new doc comment.this PR; happy to extend the SplitTree Swift tests if reviewers want
a programmatic regression there.
Risks / open questions
equalized()is recursive, so the optionresets manual resizes in the whole window on any create/close.
Could be scoped to the affected sub-split only; chose whole-window
to match user intent ('always equal') and the existing PR macOS: equalize splits when double tapping on SplitView divider #9524
double-click behavior. Happy to narrow it if you'd prefer.
a half-feature, but I didn't add Linux end-to-end tests. The Swift
side is the platform I actually run.
falsefor safety; if you'd rathership it
trueas the new default I can flip it in a follow-upcommit.
AI disclosure (per AI_POLICY.md)
This PR was authored with AI assistance via OpenCode + Claude
(opencode.ai, model
claude-opus-4-7) used for codebase research,design discussion, and code drafting. The patch is small (~50 lines)
and the human author has read every changed line, understands the
ownership of
surfaceTree/Surface.Tree, and can explain whyequalizing before
replaceSurfaceTree/setTreerather than afteris the right call (avoids touching the
closingActionguard, keepsundo blocks consistent).