Yep. AI rewrote the whole thing.
This commit is contained in:
150
Downterm/CommandNotch/Models/WorkspaceRegistry.swift
Normal file
150
Downterm/CommandNotch/Models/WorkspaceRegistry.swift
Normal file
@@ -0,0 +1,150 @@
|
||||
import SwiftUI
|
||||
|
||||
@MainActor
|
||||
final class WorkspaceRegistry: ObservableObject {
|
||||
static let shared = WorkspaceRegistry(store: UserDefaultsWorkspaceStore())
|
||||
|
||||
@Published private(set) var workspaceSummaries: [WorkspaceSummary]
|
||||
|
||||
private let store: any WorkspaceStoreType
|
||||
private var controllers: [WorkspaceID: WorkspaceController] = [:]
|
||||
private let controllerFactory: @MainActor (WorkspaceSummary) -> WorkspaceController
|
||||
|
||||
init(
|
||||
initialWorkspaces: [WorkspaceSummary]? = nil,
|
||||
store: (any WorkspaceStoreType)? = nil,
|
||||
controllerFactory: @escaping @MainActor (WorkspaceSummary) -> WorkspaceController = { summary in
|
||||
WorkspaceController(summary: summary)
|
||||
}
|
||||
) {
|
||||
let resolvedStore = store ?? UserDefaultsWorkspaceStore()
|
||||
let resolvedWorkspaces = initialWorkspaces ?? resolvedStore.loadWorkspaceSummaries()
|
||||
|
||||
self.store = resolvedStore
|
||||
self.controllerFactory = controllerFactory
|
||||
self.workspaceSummaries = resolvedWorkspaces
|
||||
|
||||
for summary in resolvedWorkspaces {
|
||||
controllers[summary.id] = controllerFactory(summary)
|
||||
}
|
||||
|
||||
_ = ensureWorkspaceExists()
|
||||
}
|
||||
|
||||
var defaultWorkspaceID: WorkspaceID {
|
||||
ensureWorkspaceExists()
|
||||
}
|
||||
|
||||
var defaultWorkspaceController: WorkspaceController {
|
||||
let workspaceID = ensureWorkspaceExists()
|
||||
guard let controller = controllers[workspaceID] else {
|
||||
let summary = WorkspaceSummary(id: workspaceID, name: "Main")
|
||||
let controller = controllerFactory(summary)
|
||||
controllers[workspaceID] = controller
|
||||
return controller
|
||||
}
|
||||
return controller
|
||||
}
|
||||
|
||||
func allWorkspaceSummaries() -> [WorkspaceSummary] {
|
||||
workspaceSummaries
|
||||
}
|
||||
|
||||
func summary(for id: WorkspaceID) -> WorkspaceSummary? {
|
||||
workspaceSummaries.first { $0.id == id }
|
||||
}
|
||||
|
||||
func controller(for id: WorkspaceID) -> WorkspaceController? {
|
||||
controllers[id]
|
||||
}
|
||||
|
||||
func canDeleteWorkspace(id: WorkspaceID) -> Bool {
|
||||
workspaceSummaries.count > 1 && workspaceSummaries.contains { $0.id == id }
|
||||
}
|
||||
|
||||
func deletionFallbackWorkspaceID(
|
||||
forDeleting id: WorkspaceID,
|
||||
preferredFallback preferredFallbackID: WorkspaceID? = nil
|
||||
) -> WorkspaceID? {
|
||||
let candidates = workspaceSummaries.filter { $0.id != id }
|
||||
|
||||
if let preferredFallbackID,
|
||||
candidates.contains(where: { $0.id == preferredFallbackID }) {
|
||||
return preferredFallbackID
|
||||
}
|
||||
|
||||
return candidates.first?.id
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func ensureWorkspaceExists() -> WorkspaceID {
|
||||
if let existing = workspaceSummaries.first {
|
||||
return existing.id
|
||||
}
|
||||
return createWorkspace(named: "Main")
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func createWorkspace(named name: String? = nil) -> WorkspaceID {
|
||||
let workspaceName = resolvedWorkspaceName(from: name)
|
||||
let summary = WorkspaceSummary(name: workspaceName)
|
||||
workspaceSummaries.append(summary)
|
||||
controllers[summary.id] = controllerFactory(summary)
|
||||
persistWorkspaceSummaries()
|
||||
return summary.id
|
||||
}
|
||||
|
||||
func renameWorkspace(id: WorkspaceID, to name: String) {
|
||||
let trimmed = name.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
guard !trimmed.isEmpty else { return }
|
||||
guard let index = workspaceSummaries.firstIndex(where: { $0.id == id }) else { return }
|
||||
|
||||
workspaceSummaries[index].name = trimmed
|
||||
controllers[id]?.rename(to: trimmed)
|
||||
persistWorkspaceSummaries()
|
||||
}
|
||||
|
||||
@discardableResult
|
||||
func deleteWorkspace(id: WorkspaceID) -> Bool {
|
||||
guard canDeleteWorkspace(id: id) else { return false }
|
||||
workspaceSummaries.removeAll { $0.id == id }
|
||||
controllers.removeValue(forKey: id)
|
||||
_ = ensureWorkspaceExists()
|
||||
persistWorkspaceSummaries()
|
||||
return true
|
||||
}
|
||||
|
||||
func updateAllWorkspacesFontSizes(_ size: CGFloat) {
|
||||
for controller in controllers.values {
|
||||
controller.updateAllFontSizes(size)
|
||||
}
|
||||
}
|
||||
|
||||
func updateAllWorkspacesThemes(_ theme: TerminalTheme) {
|
||||
for controller in controllers.values {
|
||||
controller.updateAllThemes(theme)
|
||||
}
|
||||
}
|
||||
|
||||
private func resolvedWorkspaceName(from proposedName: String?) -> String {
|
||||
let trimmed = proposedName?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
|
||||
if !trimmed.isEmpty {
|
||||
return trimmed
|
||||
}
|
||||
|
||||
let existing = Set(workspaceSummaries.map(\.name))
|
||||
if !existing.contains("Main") {
|
||||
return "Main"
|
||||
}
|
||||
|
||||
var index = 2
|
||||
while existing.contains("Workspace \(index)") {
|
||||
index += 1
|
||||
}
|
||||
return "Workspace \(index)"
|
||||
}
|
||||
|
||||
private func persistWorkspaceSummaries() {
|
||||
store.saveWorkspaceSummaries(workspaceSummaries)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user