Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 3 additions & 49 deletions Sources/TabManager+EqualizeSplits.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import Bonsplit
import CoreGraphics
import Foundation

extension TabManager {
Expand All @@ -16,16 +14,12 @@ extension TabManager {
}

@discardableResult
private func equalizeSplitsOnce(in tab: Workspace) -> EqualizeSplitsResult {
var foundSplit = false
var allSucceeded = true
equalizeSplits(
private func equalizeSplitsOnce(in tab: Workspace) -> TerminalController.EqualizeSplitsResult {
TerminalController.equalizeSplitsProportionally(
in: tab.bonsplitController.treeSnapshot(),
controller: tab.bonsplitController,
foundSplit: &foundSplit,
allSucceeded: &allSucceeded
fromExternal: true
)
return EqualizeSplitsResult(foundSplit: foundSplit, allSucceeded: allSucceeded)
}

private func scheduleEqualizeSplitsFollowUp(tabId: UUID) {
Expand All @@ -44,44 +38,4 @@ extension TabManager {
}
}

private func equalizeSplits(
in node: ExternalTreeNode,
controller: BonsplitController,
foundSplit: inout Bool,
allSucceeded: inout Bool
) {
switch node {
case .pane:
return
case .split(let splitNode):
foundSplit = true
if let splitId = UUID(uuidString: splitNode.id) {
if !controller.setDividerPosition(0.5, forSplit: splitId, fromExternal: true) {
allSucceeded = false
}
} else {
allSucceeded = false
}

equalizeSplits(
in: splitNode.first,
controller: controller,
foundSplit: &foundSplit,
allSucceeded: &allSucceeded
)
equalizeSplits(
in: splitNode.second,
controller: controller,
foundSplit: &foundSplit,
allSucceeded: &allSucceeded
)
}
}

private struct EqualizeSplitsResult {
let foundSplit: Bool
let allSucceeded: Bool

var didFullyEqualize: Bool { foundSplit && allSucceeded }
}
}
82 changes: 48 additions & 34 deletions Sources/TerminalController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5112,54 +5112,68 @@ class TerminalController {
v2MainSync {
guard let ws = v2ResolveWorkspace(params: params, tabManager: tabManager) else { return }
let tree = ws.bonsplitController.treeSnapshot()
let success = v2ProportionalEqualize(node: tree, controller: ws.bonsplitController, orientationFilter: orientationFilter)
let equalizeResult = Self.equalizeSplitsProportionally(
in: tree,
controller: ws.bonsplitController,
fromExternal: true,
orientationFilter: orientationFilter
)
result = .ok([
"workspace_id": ws.id.uuidString,
"workspace_ref": v2Ref(kind: .workspace, uuid: ws.id),
"equalized": success
"equalized": equalizeResult.foundSplit
])
}
return result
}

/// Count leaf panes in a tree node.
private func v2CountLeaves(_ node: ExternalTreeNode) -> Int {
switch node {
case .pane:
return 1
case .split(let s):
return v2CountLeaves(s.first) + v2CountLeaves(s.second)
}
struct EqualizeSplitsResult {
let foundSplit: Bool
let allSucceeded: Bool

var didFullyEqualize: Bool { foundSplit && allSucceeded }
}

/// Proportionally equalize splits so each leaf pane gets equal space.
/// For a split with N1 leaves on the left and N2 on the right,
/// the divider is set to N1/(N1+N2).
/// When orientationFilter is set (e.g. "vertical"), only splits matching
/// that orientation are equalized. This lets main-vertical layout equalize
/// the agent column without squishing the main pane.
/// When an orientation filter is set, only matching splits are adjusted, while leaf counts still come from the full subtree.
@discardableResult
private func v2ProportionalEqualize(
node: ExternalTreeNode,
static func equalizeSplitsProportionally(
in node: ExternalTreeNode,
controller: BonsplitController,
fromExternal: Bool,
orientationFilter: String? = nil
) -> Bool {
guard case .split(let s) = node else { return false }
guard let splitId = UUID(uuidString: s.id) else { return false }

var didEqualize = false
if orientationFilter == nil || s.orientation == orientationFilter {
let leftLeaves = v2CountLeaves(s.first)
let rightLeaves = v2CountLeaves(s.second)
let total = leftLeaves + rightLeaves
let position = CGFloat(leftLeaves) / CGFloat(total)
controller.setDividerPosition(position, forSplit: splitId, fromExternal: true)
didEqualize = true
}

let l = v2ProportionalEqualize(node: s.first, controller: controller, orientationFilter: orientationFilter)
let r = v2ProportionalEqualize(node: s.second, controller: controller, orientationFilter: orientationFilter)
return didEqualize || l || r
) -> EqualizeSplitsResult {
var foundSplit = false
var allSucceeded = true

@discardableResult
func equalize(_ node: ExternalTreeNode) -> Int {
switch node {
case .pane:
return 1
case .split(let split):
let firstLeafCount = equalize(split.first)
let secondLeafCount = equalize(split.second)
let totalLeafCount = firstLeafCount + secondLeafCount

if orientationFilter == nil || split.orientation == orientationFilter {
foundSplit = true
if let splitId = UUID(uuidString: split.id) {
let position = CGFloat(firstLeafCount) / CGFloat(totalLeafCount)
if !controller.setDividerPosition(position, forSplit: splitId, fromExternal: fromExternal) {
allSucceeded = false
}
} else {
allSucceeded = false
}
}

return totalLeafCount
}
}

equalize(node)
return EqualizeSplitsResult(foundSplit: foundSplit, allSucceeded: allSucceeded)
}

private func v2WorkspaceRemoteConfigure(params: [String: Any]) -> V2CallResult {
Expand Down
Loading