Skip to content

Commit 2393b71

Browse files
authored
refactor: extract command-palette helpers and dethunk ContentView.body (CV1, CV2) (#65)
CV1 — ContentView was a single 7000-line struct with ~4,000 lines of command-palette orchestration written as private funcs mutating @State directly. Moves 52 pure/computation functions (fuzzy-search corpus building, result fingerprinting/diffing, shortcut resolution, switcher entry construction, context-snapshot building — none of which touch @State) into a new extension file, Sources/ContentView+CommandPalette.swift. This is the conservative extraction: SwiftUI's @State can't be split across files, so the @State/@ObservedObject properties, the view body, and the @State-mutating activation-dispatch / rename / edit-description flow orchestration all remain on ContentView in ContentView.swift. 19 members the moved functions touch (10 nested command-palette model types, 6 small helper funcs, 3 computed properties) were widened from private to internal so the extension can see them; behavior is unchanged. Full controller-based extraction of the @State-owning orchestration is a follow-up. CV2 — ContentView.body reassigned a local through 15+ AnyView(view.onReceive(...)) steps to work around Swift's type checker (each step needed a stable erased type to reassign into a var). Splits the ~30 onChange/onReceive attachments into 9 ViewBuilder-composed helper functions chained via a small number of local let bindings, removing all AnyView type erasure from the body while keeping every closure body byte-for-byte identical. The body's window-accessor closure also mutated AppKit window state (identifier, titlebar, movability, transparency, glass effect, window decorations) directly from the view layer. Moves that logic into a new AppDelegate.configureMainWindow(...) method; the view now makes one call and keeps only the @State bookkeeping (observedWindow, isFullScreen, titlebarPadding) it actually owns. makeViewHierarchyTransparent became a static func on ContentView since it never touched instance state. project.pbxproj: registers ContentView+CommandPalette.swift (file reference + build file, mirroring ContentView.swift's 4 entries).
1 parent 10d8f12 commit 2393b71

4 files changed

Lines changed: 1584 additions & 1557 deletions

File tree

GhosttyTabs.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
A5001001 /* ProgramaApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5001011 /* ProgramaApp.swift */; };
1111
A5FF0007 /* SettingDefinition.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5FF0017 /* SettingDefinition.swift */; };
1212
A5001002 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5001012 /* ContentView.swift */; };
13+
A5FF0005 /* ContentView+CommandPalette.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5FF0015 /* ContentView+CommandPalette.swift */; };
1314
E62155868BB29FEB5DAAAF25 /* SidebarSelectionState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9AD52285508B1D6A9875E7B3 /* SidebarSelectionState.swift */; };
1415
B9000018A1B2C3D4E5F60719 /* WindowDragHandleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B9000017A1B2C3D4E5F60719 /* WindowDragHandleView.swift */; };
1516
A5001003 /* TabManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = A5001013 /* TabManager.swift */; };
@@ -225,6 +226,7 @@
225226
A5001011 /* ProgramaApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgramaApp.swift; sourceTree = "<group>"; };
226227
A5FF0017 /* SettingDefinition.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingDefinition.swift; sourceTree = "<group>"; };
227228
A5001012 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
229+
A5FF0015 /* ContentView+CommandPalette.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContentView+CommandPalette.swift"; sourceTree = "<group>"; };
228230
9AD52285508B1D6A9875E7B3 /* SidebarSelectionState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SidebarSelectionState.swift; sourceTree = "<group>"; };
229231
B9000017A1B2C3D4E5F60719 /* WindowDragHandleView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowDragHandleView.swift; sourceTree = "<group>"; };
230232
A5001013 /* TabManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabManager.swift; sourceTree = "<group>"; };
@@ -487,6 +489,7 @@
487489
A5001011 /* ProgramaApp.swift */,
488490
A5FF0017 /* SettingDefinition.swift */,
489491
A5001012 /* ContentView.swift */,
492+
A5FF0015 /* ContentView+CommandPalette.swift */,
490493
9AD52285508B1D6A9875E7B3 /* SidebarSelectionState.swift */,
491494
B9000017A1B2C3D4E5F60719 /* WindowDragHandleView.swift */,
492495
A50012F0 /* Backport.swift */,
@@ -808,6 +811,7 @@
808811
A5001001 /* ProgramaApp.swift in Sources */,
809812
A5FF0007 /* SettingDefinition.swift in Sources */,
810813
A5001002 /* ContentView.swift in Sources */,
814+
A5FF0005 /* ContentView+CommandPalette.swift in Sources */,
811815
E62155868BB29FEB5DAAAF25 /* SidebarSelectionState.swift in Sources */,
812816
B9000018A1B2C3D4E5F60719 /* WindowDragHandleView.swift in Sources */,
813817
A50012F1 /* Backport.swift in Sources */,

Sources/AppDelegate.swift

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10392,6 +10392,97 @@ final class AppDelegate: NSObject, NSApplicationDelegate, UNUserNotificationCent
1039210392
}
1039310393
#endif
1039410394

10395+
/// Configures a Programa main window's AppKit-level presentation (identifier,
10396+
/// titlebar, movability, transparency, glass effect, decorations) and registers
10397+
/// it for window-context tracking, then installs the file-drop overlay.
10398+
///
10399+
/// Extracted verbatim from `ContentView`'s `WindowAccessor` trailing closure
10400+
/// (nuclear-review CV2b) so this AppKit window mutation lives with the
10401+
/// window-context layer instead of the SwiftUI view layer. `ContentView` still
10402+
/// owns tracking its own `@State` (`observedWindow`, `isFullScreen`,
10403+
/// `titlebarPadding`) — this method returns the computed titlebar padding so
10404+
/// the caller can decide whether to update that `@State`.
10405+
@discardableResult
10406+
func configureMainWindow(
10407+
_ window: NSWindow,
10408+
windowId: UUID,
10409+
windowIdentifier: String,
10410+
tabManager: TabManager,
10411+
sidebarState: SidebarState,
10412+
sidebarSelectionState: SidebarSelectionState,
10413+
sidebarBlendMode: String,
10414+
bgGlassEnabled: Bool,
10415+
bgGlassTintHex: String,
10416+
bgGlassTintOpacity: Double
10417+
) -> CGFloat {
10418+
window.identifier = NSUserInterfaceItemIdentifier(windowIdentifier)
10419+
window.titlebarAppearsTransparent = true
10420+
// Keep window immovable; the sidebar's WindowDragHandleView handles
10421+
// drag-to-move via performDrag with temporary movable override.
10422+
// isMovableByWindowBackground=true breaks tab reordering, and
10423+
// isMovable=true blocks clicks on sidebar buttons in minimal mode.
10424+
window.isMovableByWindowBackground = false
10425+
window.isMovable = false
10426+
window.styleMask.insert(.fullSizeContentView)
10427+
10428+
// Keep content below the titlebar so drags on Bonsplit's tab bar don't
10429+
// get interpreted as window drags.
10430+
let computedTitlebarHeight = window.frame.height - window.contentLayoutRect.height
10431+
let nextTitlebarPadding = max(28, min(72, computedTitlebarHeight))
10432+
#if DEBUG
10433+
if ProcessInfo.processInfo.environment["PROGRAMA_UI_TEST_MODE"] == "1" {
10434+
UpdateLogStore.shared.append("ui test window accessor: id=\(windowIdentifier) visible=\(window.isVisible)")
10435+
}
10436+
#endif
10437+
// User settings decide whether window glass is active. The native Tahoe
10438+
// NSGlassEffectView path vs the older NSVisualEffectView fallback is chosen
10439+
// inside WindowGlassEffect.apply.
10440+
let currentThemeBackground = GhosttyBackgroundTheme.currentColor()
10441+
let shouldApplyWindowGlass = cmuxShouldApplyWindowGlass(
10442+
sidebarBlendMode: sidebarBlendMode,
10443+
bgGlassEnabled: bgGlassEnabled,
10444+
glassEffectAvailable: WindowGlassEffect.isAvailable
10445+
)
10446+
let shouldForceTransparentHosting =
10447+
shouldApplyWindowGlass || currentThemeBackground.alphaComponent < 0.999
10448+
10449+
if shouldForceTransparentHosting {
10450+
window.isOpaque = false
10451+
// Keep the window clear whenever translucency is active. Relying only on
10452+
// terminal focus-driven updates can leave stale opaque window fills.
10453+
window.backgroundColor = NSColor.white.withAlphaComponent(0.001)
10454+
// Configure contentView hierarchy for transparency.
10455+
if let contentView = window.contentView {
10456+
ContentView.makeViewHierarchyTransparent(contentView)
10457+
}
10458+
} else {
10459+
// Browser-focused workspaces may not have an active terminal panel to refresh
10460+
// the NSWindow background. Keep opaque theme changes applied here as well.
10461+
window.backgroundColor = currentThemeBackground
10462+
window.isOpaque = currentThemeBackground.alphaComponent >= 0.999
10463+
}
10464+
10465+
if shouldApplyWindowGlass {
10466+
// Apply liquid glass effect to the window with tint from settings
10467+
let tintColor = (NSColor(hex: bgGlassTintHex) ?? .black).withAlphaComponent(bgGlassTintOpacity)
10468+
WindowGlassEffect.apply(to: window, tintColor: tintColor)
10469+
} else {
10470+
WindowGlassEffect.remove(from: window)
10471+
}
10472+
AppDelegate.shared?.attachUpdateAccessory(to: window)
10473+
AppDelegate.shared?.applyWindowDecorations(to: window)
10474+
AppDelegate.shared?.registerMainWindow(
10475+
window,
10476+
windowId: windowId,
10477+
tabManager: tabManager,
10478+
sidebarState: sidebarState,
10479+
sidebarSelectionState: sidebarSelectionState
10480+
)
10481+
installFileDropOverlay(on: window, tabManager: tabManager)
10482+
10483+
return nextTitlebarPadding
10484+
}
10485+
1039510486
}
1039610487

1039710488
@MainActor

0 commit comments

Comments
 (0)