Skip to content

Commit

Permalink
Move to internalized theme storage
Browse files Browse the repository at this point in the history
  • Loading branch information
mattmassicotte committed Jul 19, 2024
1 parent c443a5c commit d4290a2
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 61 deletions.
36 changes: 27 additions & 9 deletions Edit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
C97640F42C403777002C94BF /* RustExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C97640F32C403777002C94BF /* RustExtension.swift */; };
C97640F52C40377D002C94BF /* RustExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = C97640F32C403777002C94BF /* RustExtension.swift */; };
C97640F82C403791002C94BF /* ChimeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C9FE52F42A7539B100CACA1A /* ChimeKit.framework */; };
C976D7E62C4A86F900CC6EA6 /* ThemePark in Frameworks */ = {isa = PBXBuildFile; productRef = C976D7E52C4A86F900CC6EA6 /* ThemePark */; };
C979187B2A9CC1110046EAF1 /* SearchItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C97918752A9CBEF20046EAF1 /* SearchItem.swift */; };
C979187C2A9CC1190046EAF1 /* RoundedCorners.swift in Sources */ = {isa = PBXBuildFile; fileRef = C97918792A9CBF8C0046EAF1 /* RoundedCorners.swift */; };
C979187D2A9CC1200046EAF1 /* ItemBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = C97918772A9CBF330046EAF1 /* ItemBackground.swift */; };
Expand Down Expand Up @@ -197,7 +198,6 @@
C9E0BA312BD2C1FA007AF034 /* SettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E0BA2F2BD2C1EF007AF034 /* SettingsView.swift */; };
C9E0BA352BD2C7F2007AF034 /* ThemeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E0BA342BD2C7F2007AF034 /* ThemeView.swift */; };
C9E0BA372BD2C96D007AF034 /* ThemeTile.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E0BA362BD2C96D007AF034 /* ThemeTile.swift */; };
C9E0BA3E2BD2EB54007AF034 /* ThemePark in Frameworks */ = {isa = PBXBuildFile; productRef = C9E0BA3D2BD2EB54007AF034 /* ThemePark */; };
C9E0BA422BD52732007AF034 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E0BA412BD52732007AF034 /* Theme.swift */; };
C9E877FC2A9F4B820018340C /* TrailingSidebar.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E877FB2A9F4B820018340C /* TrailingSidebar.swift */; };
C9E878042A9F53530018340C /* UIPlaceholder.swift in Sources */ = {isa = PBXBuildFile; fileRef = C9E878032A9F53530018340C /* UIPlaceholder.swift */; };
Expand Down Expand Up @@ -1255,6 +1255,7 @@
files = (
C9439A732C3EB5260020DDF5 /* libSyntaxService.a in Frameworks */,
C9439A722C3EB5140020DDF5 /* libHighlighting.a in Frameworks */,
C976D7E62C4A86F900CC6EA6 /* ThemePark in Frameworks */,
C96B62002BDA71E400561DE8 /* libStatus.a in Frameworks */,
C96B61FF2BDA71B200561DE8 /* libUIUtility.a in Frameworks */,
C96B61FE2BDA719100561DE8 /* libGutter.a in Frameworks */,
Expand All @@ -1273,7 +1274,6 @@
C9BFA1B72BC162EF00E86487 /* NSUI in Frameworks */,
C9BFA1B02BC0927A00E86487 /* Glyph in Frameworks */,
C95B91362BD98CBD006FDD00 /* RelativeCollections in Frameworks */,
C9E0BA3E2BD2EB54007AF034 /* ThemePark in Frameworks */,
C929316A2B822BA700C64DDE /* libTheme.a in Frameworks */,
C95B913E2BD98D01006FDD00 /* SwiftTreeSitterLayer in Frameworks */,
C92931692B822B7B00C64DDE /* ColorToolbox in Frameworks */,
Expand Down Expand Up @@ -2379,6 +2379,7 @@
buildRules = (
);
dependencies = (
C976D7E82C4A871400CC6EA6 /* PBXTargetDependency */,
C96B62022BDA71FE00561DE8 /* PBXTargetDependency */,
C96B61FB2BDA714000561DE8 /* PBXTargetDependency */,
C96B61F52BDA70E000561DE8 /* PBXTargetDependency */,
Expand All @@ -2396,7 +2397,6 @@
C92931682B822B7B00C64DDE /* ColorToolbox */,
C9BFA1AF2BC0927A00E86487 /* Glyph */,
C9BFA1B62BC162EF00E86487 /* NSUI */,
C9E0BA3D2BD2EB54007AF034 /* ThemePark */,
C95B91282BD98C3B006FDD00 /* Rearrange */,
C95B912C2BD98C50006FDD00 /* Neon */,
C95B91332BD98CA1006FDD00 /* SwiftTreeSitter */,
Expand All @@ -2407,6 +2407,7 @@
C96B61FC2BDA714700561DE8 /* ScrollViewPlus */,
C96B62052BDA721100561DE8 /* SourceView */,
C9439A702C3EB4410020DDF5 /* TreeSitterParsers */,
C976D7E52C4A86F900CC6EA6 /* ThemePark */,
);
productName = EditKit;
productReference = C92931422B80CC6700C64DDE /* EditKit.framework */;
Expand Down Expand Up @@ -3247,8 +3248,8 @@
C9C568562B7418B60093C068 /* XCRemoteSwiftPackageReference "Lowlight" */,
C9BFA1A12BBF4FA200E86487 /* XCRemoteSwiftPackageReference "nsui" */,
C9BFA1AE2BC0927A00E86487 /* XCRemoteSwiftPackageReference "Glyph" */,
C9E0BA3A2BD2EB05007AF034 /* XCRemoteSwiftPackageReference "ThemePark" */,
C93F72252BF0F9290021ACF3 /* XCRemoteSwiftPackageReference "Sparkle" */,
C976D7E42C4A86F800CC6EA6 /* XCRemoteSwiftPackageReference "ThemePark" */,
);
productRefGroup = C9FE529A2A7525D000CACA1A /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -4049,6 +4050,10 @@
target = C9FE52F32A7539B100CACA1A /* ChimeKit */;
targetProxy = C97640F62C40378C002C94BF /* PBXContainerItemProxy */;
};
C976D7E82C4A871400CC6EA6 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
productRef = C976D7E72C4A871400CC6EA6 /* ThemePark */;
};
C97918722A9CBD6B0046EAF1 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = C9FE539A2A76709D00CACA1A /* Status */;
Expand Down Expand Up @@ -5353,6 +5358,14 @@
revision = d563ef0ba6c1c91aa6bcee406577b8826baa1f69;
};
};
C976D7E42C4A86F800CC6EA6 /* XCRemoteSwiftPackageReference "ThemePark" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/ChimeHQ/ThemePark";
requirement = {
kind = revision;
revision = 2ccbf37a0c7e52c7b20aadabd8e8cbbb2b25b9a8;
};
};
C97918C32A9D4A510046EAF1 /* XCRemoteSwiftPackageReference "FuzzyFind" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/truizlop/FuzzyFind";
Expand Down Expand Up @@ -5630,6 +5643,16 @@
package = C926738F2B078D3200B3CE2F /* XCRemoteSwiftPackageReference "Neon" */;
productName = Neon;
};
C976D7E52C4A86F900CC6EA6 /* ThemePark */ = {
isa = XCSwiftPackageProductDependency;
package = C976D7E42C4A86F800CC6EA6 /* XCRemoteSwiftPackageReference "ThemePark" */;
productName = ThemePark;
};
C976D7E72C4A871400CC6EA6 /* ThemePark */ = {
isa = XCSwiftPackageProductDependency;
package = C976D7E42C4A86F800CC6EA6 /* XCRemoteSwiftPackageReference "ThemePark" */;
productName = ThemePark;
};
C97918C62A9D4A6A0046EAF1 /* FuzzyFind */ = {
isa = XCSwiftPackageProductDependency;
package = C97918C32A9D4A510046EAF1 /* XCRemoteSwiftPackageReference "FuzzyFind" */;
Expand Down Expand Up @@ -5744,11 +5767,6 @@
package = C9FE53EB2A7A5D9700CACA1A /* XCRemoteSwiftPackageReference "Extendable" */;
productName = ExtendableHost;
};
C9E0BA3D2BD2EB54007AF034 /* ThemePark */ = {
isa = XCSwiftPackageProductDependency;
package = C9E0BA3A2BD2EB05007AF034 /* XCRemoteSwiftPackageReference "ThemePark" */;
productName = ThemePark;
};
C9F79DDD2A87E656005ED8E9 /* Outline */ = {
isa = XCSwiftPackageProductDependency;
productName = Outline;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"originHash" : "7ec6ccb9bc276a295422e18b1a495ba45c60ca70b5912320b7f399276466ef72",
"originHash" : "149adbfbae957f76ac903a7309649365bc7a1ca5a075d5070b19f145bb016507",
"pins" : [
{
"identity" : "asyncxpcconnection",
Expand Down Expand Up @@ -237,7 +237,7 @@
"kind" : "remoteSourceControl",
"location" : "https://github.com/ChimeHQ/ThemePark",
"state" : {
"revision" : "fff8ae0521d76e81acd5c72ad39144ad10f1d489"
"revision" : "2ccbf37a0c7e52c7b20aadabd8e8cbbb2b25b9a8"
}
},
{
Expand Down
2 changes: 1 addition & 1 deletion Edit/Modules/PreferencesWindow/ThemeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ final class ThemeModel {
@MainActor
struct ThemeView: View {
@State private var model: ThemeModel
@AppStorage("theme-identifier") private var themeId: String = ""
@AppStorage("CurrentTheme", store: UserDefaults.sharedSuite) private var themeId: String = ""

private let adaptiveColumn = [
GridItem(.adaptive(minimum: 150))
Expand Down
2 changes: 1 addition & 1 deletion Edit/Modules/ProjectWindow/ProjectWindowRoot.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Utility
struct ProjectWindowRoot<Content: View>: View {
@Environment(WindowStateModel.self) private var model
@Environment(\.windowState) private var windowState
@AppStorage("theme-identifier") private var themeId: String = ""
@AppStorage("CurrentTheme", store: UserDefaults.sharedSuite) private var themeId: String = ""

let content: Content

Expand Down
6 changes: 1 addition & 5 deletions Edit/Modules/ProjectWindow/WindowStateModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,7 @@ public final class WindowStateModel {
self.documentContext = context
self.themeStore = themeStore

let theme = UserDefaults.standard
.string(forKey: "theme-identifier")
.map { themeStore.theme(with: $0) }

self.currentTheme = theme ?? Theme.fallback
self.currentTheme = ThemeStore.currentTheme ?? Theme.fallback
}

func windowStateChanged(_ old: WindowStateObserver.State, _ new: WindowStateObserver.State) {
Expand Down
117 changes: 74 additions & 43 deletions Edit/Modules/Theme/ThemeStore.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import ThemePark
@MainActor
public final class ThemeStore {
private var themeCache = [Theme.Identity: Theme]()
private var themeURLs = [Theme.Identity: URL]()

public init() {
}
Expand Down Expand Up @@ -39,20 +40,41 @@ public final class ThemeStore {

private func loadXcodeThemes() {
#if os(macOS)
for (name, theme) in XcodeTheme.all {
for url in XcodeTheme.all {
guard let theme = try? XcodeTheme(contentsOf: url) else { continue }

let name = url.deletingPathExtension().lastPathComponent
let identity = Theme.Identity(source: .xcode, name: name)

cacheStyler(theme, with: identity)
themeURLs[identity] = url
}
#endif
}

private func loadTextMateThemes() {
#if os(macOS)
for theme in TextMateTheme.all {
for url in TextMateTheme.all {
guard let theme = try? TextMateTheme(contentsOf: url) else { continue }

let identity = Theme.Identity(source: .textmate, name: theme.name)

cacheStyler(theme, with: identity)
themeURLs[identity] = url
}
#endif
}

private func loadBBEditThemes() {
#if os(macOS)
for url in BBEditTheme.all {
guard let theme = try? BBEditTheme(contentsOf: url) else { continue }

let name = url.deletingPathExtension().lastPathComponent
let identity = Theme.Identity(source: .bbedit, name: name)

cacheStyler(theme, with: identity)
themeURLs[identity] = url
}
#endif
}
Expand All @@ -66,30 +88,7 @@ public final class ThemeStore {
private func loadThemes() {
loadXcodeThemes()
loadTextMateThemes()

guard let containerURL = FileManager.default.appGroupContainerURL else { return }

let themeCacheDir = containerURL.appending(path: "Library/Caches/Themes", directoryHint: .isDirectory)

try? FileManager.default.createDirectory(at: themeCacheDir, withIntermediateDirectories: true)

for (identity, theme) in themeCache {
let codableTheme = CodableTheme(styler: CodableStyler(theme), identity: identity)
let url = themeCacheDir.appending(path: identity.storageString, directoryHint: .notDirectory)

do {
let data = try JSONEncoder().encode(codableTheme)

try data.write(to: url)
} catch {
print("failed to write out current theme: ", error)
}
}

let names = themeCache.keys.map { $0.storageString }
UserDefaults.sharedSuite?.setValue(names, forKey: "ThemeIdentities")

print(Self.availableIdentities)
loadBBEditThemes()
}

public var all: [Theme.Identity: Theme] {
Expand All @@ -104,25 +103,51 @@ extension ThemeStore {
FileManager.default.appGroupContainerURL?.appending(path: "CurrentTheme.json")
}

public static var availableIdentities: Set<Theme.Identity> {
guard let names = UserDefaults.sharedSuite?.array(forKey: "ThemeIdentities") as? [String] else {
return []
}

return Set(names.compactMap { Theme.Identity(storageString: $0) })
public static var copiedThemesURL: URL? {
FileManager.default.appGroupContainerURL?.appending(path: "Themes")
}

// public static var availableIdentities: Set<Theme.Identity> {
// guard let names = UserDefaults.sharedSuite?.array(forKey: "ThemeIdentities") as? [String] else {
// return []
// }
//
// return Set(names.compactMap { Theme.Identity(storageString: $0) })
// }

public static var currentTheme: Theme? {
guard let url = ThemeStore.currentThemeURL else {
guard let dirURL = Self.copiedThemesURL else {
return nil
}

do {
let data = try Data(contentsOf: url)
guard let storageString = UserDefaults.sharedSuite?.string(forKey: "CurrentTheme") else {
return nil
}

guard let identity = Theme.Identity(storageString: storageString) else {
return nil
}

let codableTheme = try JSONDecoder().decode(CodableTheme.self, from: data)
let themeURL = dirURL.appending(path: identity.storageString, directoryHint: .notDirectory)

return Theme(identity: codableTheme.identity, styler: codableTheme.styler)
do {
switch identity.source {
case .xcode:
let theme = try XcodeTheme(contentsOf: themeURL)

return Theme(identity: identity, styler: theme)
case .textmate:
let theme = try TextMateTheme(contentsOf: themeURL)

return Theme(identity: identity, styler: theme)
case .bbedit:
let theme = try BBEditTheme(contentsOf: themeURL)

return Theme(identity: identity, styler: theme)
case .chime:
assertionFailure("What are we supposed to do here exactly?")
return Theme.fallback
}
} catch {
print("failed to load current theme: ", error)

Expand All @@ -131,18 +156,24 @@ extension ThemeStore {
}

public func updateCurrentTheme(with identity: Theme.Identity) {
guard let url = ThemeStore.currentThemeURL else {
UserDefaults.sharedSuite?.setValue(identity.storageString, forKey: "CurrentTheme")

guard let url = Self.copiedThemesURL else {
return
}

let theme = theme(with: identity)

let codableTheme = CodableTheme(styler: CodableStyler(theme), identity: identity)
guard let source = themeURLs[identity] else {
return
}

do {
let data = try JSONEncoder().encode(codableTheme)

try data.write(to: url)
let destination = url.appending(path: identity.storageString, directoryHint: .notDirectory)

try? FileManager.default.removeItem(at: destination)
try? FileManager.default.createDirectory(at: url, withIntermediateDirectories: true)
try FileManager.default.copyItem(at: source, to: destination)

} catch {
print("failed to write out current theme: ", error)
}
Expand Down

0 comments on commit d4290a2

Please sign in to comment.