Files
Termind/TFM/Features/Workspaces/ClosedWorkspaceRecord.swift

64 lines
2.6 KiB
Swift

// SPDX-FileCopyrightText: 2026 Kaede Akino
// SPDX-License-Identifier: GPL-3.0-only
import Foundation
import TermindApplication
import TermindDomain
/// Only saved-host references and presentation state survive an app restart.
struct ClosedWorkspaceRecord: Codable, Identifiable {
let id: UUID
let title: String
let symbol: String
let layout: WorkspaceTemplateLayout?
let paneNames: [String?]
let focusedPaneIndex: Int
var remoteSessions: [RemoteSessionReference?]? = nil
@MainActor
init(_ workspace: Workspace, hosts: HostLibraryModel) {
let layout =
workspace.panes.contains { $0.sshSession?.isExternalTemporaryConnection == true }
? nil : workspace.workspaceTemplateLayout(in: hosts)
self.remoteSessions = workspace.panes.map { $0.sshSession?.restorableRemoteSession }
self.id = workspace.id
self.title = workspace.title(in: hosts)
self.symbol = workspace.symbol
self.layout = layout
self.paneNames = workspace.panes.map(\.customTitle)
self.focusedPaneIndex = workspace.panes.firstIndex { $0.id == workspace.focusedPaneID } ?? 0
}
@MainActor
func canRestore(in hosts: HostLibraryModel) -> Bool {
guard let layout else { return false }
return layout.isValid
&& layout.panes.allSatisfy { pane in
switch pane {
case .empty: true
case .ssh(let id), .sftp(let id): hosts.host(id)?.sshEnabled == true
case .telnet(let id): hosts.host(id)?.telnetEnabled == true
case .mosh(let id): hosts.host(id)?.isEnabled(.mosh) == true
case .eternalTerminal(let id): hosts.host(id)?.isEnabled(.eternalTerminal) == true
}
}
}
@MainActor
func restore(in hosts: HostLibraryModel) -> Workspace? {
guard canRestore(in: hosts), let layout else { return nil }
let node = layout.makeSplitNode(using: hosts).node
let workspace = Workspace(pane: node.firstPane)
workspace.layout = node
for (pane, name) in zip(workspace.panes, paneNames) { pane.customTitle = name }
for (pane, reference) in zip(workspace.panes, remoteSessions ?? []) {
pane.sshSession?.sessionPersistence.attachment = reference
}
if workspace.isSplit { workspace.customTitle = title } else { workspace.automaticTitle = title }
if workspace.panes.indices.contains(focusedPaneIndex) {
workspace.focusedPaneID = workspace.panes[focusedPaneIndex].id
}
return workspace
}
}