64 lines
2.6 KiB
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
|
|
}
|
|
}
|