92 lines
3.2 KiB
Swift
92 lines
3.2 KiB
Swift
// SPDX-FileCopyrightText: 2026 Kaede Akino
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
import Foundation
|
|
|
|
public nonisolated enum TerminalThemeAppearance: String, Codable, CaseIterable, Sendable {
|
|
case light, dark, both
|
|
|
|
public func includes(isDark: Bool) -> Bool {
|
|
self == .both || self == (isDark ? .dark : .light)
|
|
}
|
|
}
|
|
|
|
public nonisolated struct TerminalCustomTheme: Codable, Hashable, Identifiable, Sendable {
|
|
public var id: UUID
|
|
public var name: String
|
|
public var appearance: TerminalThemeAppearance
|
|
public var baseThemeName: String
|
|
public var configuration: String
|
|
|
|
public init(
|
|
id: UUID = UUID(), name: String, appearance: TerminalThemeAppearance,
|
|
baseThemeName: String, configuration: String = ""
|
|
) {
|
|
self.id = id
|
|
self.name = name
|
|
self.appearance = appearance
|
|
self.baseThemeName = baseThemeName
|
|
self.configuration = configuration
|
|
}
|
|
|
|
public var isValid: Bool {
|
|
!name.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty && !baseThemeName.isEmpty
|
|
}
|
|
|
|
public func copy(named name: String) -> Self {
|
|
var copy = self
|
|
copy.id = UUID()
|
|
copy.name = name
|
|
return copy
|
|
}
|
|
}
|
|
|
|
/// The built-in name also remembers the fallback while a custom theme is selected.
|
|
public nonisolated struct TerminalThemeSelection: Codable, Hashable, Sendable {
|
|
public var appearance: TerminalThemeAppearance
|
|
public var builtInThemeName: String
|
|
public var customThemeID: UUID?
|
|
|
|
public init(appearance: TerminalThemeAppearance, builtInThemeName: String, customThemeID: UUID? = nil) {
|
|
self.appearance = appearance
|
|
self.builtInThemeName = builtInThemeName
|
|
self.customThemeID = customThemeID
|
|
}
|
|
|
|
public var isValid: Bool { appearance != .both && !builtInThemeName.isEmpty }
|
|
}
|
|
|
|
public nonisolated struct TerminalThemeLibrary: Equatable, Sendable {
|
|
public var themes: [TerminalCustomTheme]
|
|
public var selections: [TerminalThemeSelection]
|
|
|
|
public init(themes: [TerminalCustomTheme] = [], selections: [TerminalThemeSelection] = []) {
|
|
self.themes = themes
|
|
self.selections = selections
|
|
}
|
|
|
|
public func selection(isDark: Bool) -> TerminalThemeSelection? {
|
|
selections.first { $0.appearance == (isDark ? .dark : .light) }
|
|
}
|
|
|
|
public func selectedTheme(isDark: Bool) -> TerminalCustomTheme? {
|
|
guard let id = selection(isDark: isDark)?.customThemeID else { return nil }
|
|
return themes.first { $0.id == id && $0.appearance.includes(isDark: isDark) }
|
|
}
|
|
|
|
public mutating func select(_ selection: TerminalThemeSelection) {
|
|
selections.removeAll { $0.appearance == selection.appearance }
|
|
selections.append(selection)
|
|
selections.sort { $0.appearance.rawValue < $1.appearance.rawValue }
|
|
}
|
|
|
|
public mutating func repairSelections(for id: UUID) {
|
|
for index in selections.indices where selections[index].customThemeID == id {
|
|
let isDark = selections[index].appearance == .dark
|
|
if !themes.contains(where: { $0.id == id && $0.appearance.includes(isDark: isDark) }) {
|
|
selections[index].customThemeID = nil
|
|
}
|
|
}
|
|
}
|
|
}
|