Skip to content

Commit 1434909

Browse files
committed
Support swapping suggestion feature provider
1 parent c446fd7 commit 1434909

File tree

8 files changed

+45
-81
lines changed

8 files changed

+45
-81
lines changed

Core/Package.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ let package = Package(
1616
"LaunchAgentManager",
1717
"UpdateChecker",
1818
"Logger",
19+
"UserDefaultsObserver",
1920
]
2021
),
2122
.library(
@@ -69,6 +70,7 @@ let package = Package(
6970
"ChatService",
7071
"PromptToCodeService",
7172
"ServiceUpdateMigration",
73+
"UserDefaultsObserver",
7274
.product(name: "AsyncAlgorithms", package: "swift-async-algorithms"),
7375
]
7476
),
@@ -118,6 +120,7 @@ let package = Package(
118120
.target(name: "SuggestionService", dependencies: [
119121
"GitHubCopilotService",
120122
"CodeiumService",
123+
"UserDefaultsObserver",
121124
]),
122125

123126
// MARK: - Prompt To Code
@@ -150,6 +153,7 @@ let package = Package(
150153
"Environment",
151154
"Highlightr",
152155
"Splash",
156+
"UserDefaultsObserver",
153157
.product(name: "AsyncAlgorithms", package: "swift-async-algorithms"),
154158
.product(name: "MarkdownUI", package: "swift-markdown-ui"),
155159
]
@@ -179,6 +183,7 @@ let package = Package(
179183
name: "ServiceUpdateMigration",
180184
dependencies: ["Preferences", "GitHubCopilotService"]
181185
),
186+
.target(name: "UserDefaultsObserver"),
182187

183188
// MARK: - GitHub Copilot
184189

Core/Sources/Service/GUI/RealtimeSuggestionIndicatorController.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Environment
77
import Preferences
88
import QuartzCore
99
import SwiftUI
10+
import UserDefaultsObserver
1011

1112
/// Present a tiny dot next to mouse cursor if real-time suggestion is enabled.
1213
@MainActor

Core/Sources/Service/Workspace.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Preferences
77
import SuggestionInjector
88
import SuggestionModel
99
import SuggestionService
10+
import UserDefaultsObserver
1011
import XPCShared
1112

1213
@ServiceActor
@@ -119,7 +120,7 @@ final class Workspace {
119120

120121
if _suggestionService == nil {
121122
_suggestionService = Environment.createSuggestionService(projectRootURL) {
122-
[weak self] service in
123+
[weak self] _ in
123124
guard let self else { return }
124125
for (_, filespace) in filespaces {
125126
notifyOpenFile(filespace: filespace)
@@ -178,7 +179,7 @@ final class Workspace {
178179

179180
let projectURL = try await Environment.fetchCurrentProjectRootURL(fileURL)
180181
let workspaceURL = projectURL ?? fileURL
181-
182+
182183
let workspace = {
183184
if let existed = workspaces[workspaceURL] {
184185
return existed
@@ -191,7 +192,7 @@ final class Workspace {
191192
}
192193
return Workspace(projectRootURL: workspaceURL)
193194
}()
194-
195+
195196
let filespace = workspace.createFilespaceIfNeeded(fileURL: fileURL)
196197
workspaces[workspaceURL] = workspace
197198
workspace.refreshUpdateTime()

Core/Sources/SuggestionService/SuggestionService.swift

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
1-
import CodeiumService
21
import Foundation
3-
import GitHubCopilotService
2+
import UserDefaultsObserver
43
import Preferences
54
import SuggestionModel
65

@@ -28,9 +27,13 @@ protocol SuggestionServiceProvider: SuggestionServiceType {}
2827
public final class SuggestionService: SuggestionServiceType {
2928
let projectRootURL: URL
3029
let onServiceLaunched: (SuggestionServiceType) -> Void
31-
lazy var suggestionProvider: SuggestionServiceProvider = buildService()
30+
let providerChangeObserver = UserDefaultsObserver(
31+
object: UserDefaults.shared,
32+
forKeyPaths: [UserDefaultPreferenceKeys().suggestionFeatureProvider.key],
33+
context: nil
34+
)
3235

33-
var codeiumService: CodeiumSuggestionServiceType?
36+
lazy var suggestionProvider: SuggestionServiceProvider = buildService()
3437

3538
var serviceType: SuggestionFeatureProvider {
3639
UserDefaults.shared.value(for: \.suggestionFeatureProvider)
@@ -39,6 +42,11 @@ public final class SuggestionService: SuggestionServiceType {
3942
public init(projectRootURL: URL, onServiceLaunched: @escaping (SuggestionServiceType) -> Void) {
4043
self.projectRootURL = projectRootURL
4144
self.onServiceLaunched = onServiceLaunched
45+
46+
providerChangeObserver.onChange = { [weak self] in
47+
guard let self else { return }
48+
suggestionProvider = buildService()
49+
}
4250
}
4351

4452
func buildService() -> SuggestionServiceProvider {

Core/Sources/SuggestionWidget/SuggestionWidgetController.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import Combine
66
import Environment
77
import Preferences
88
import SwiftUI
9+
import UserDefaultsObserver
910

1011
@MainActor
1112
public final class SuggestionWidgetController: NSObject {

Core/Sources/SuggestionWidget/UserDefaultsObserver.swift

Lines changed: 0 additions & 31 deletions
This file was deleted.

Core/Sources/Service/UserDefaultsObserver.swift renamed to Core/Sources/UserDefaultsObserver/UserDefaultsObserver.swift

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import Foundation
22

3-
final class UserDefaultsObserver: NSObject {
4-
var onChange: (() -> Void)?
3+
public final class UserDefaultsObserver: NSObject {
4+
public var onChange: (() -> Void)?
55
private weak var object: NSObject?
66
private let keyPaths: [String]
7-
8-
init(object: NSObject, forKeyPaths keyPaths: [String], context: UnsafeMutableRawPointer?) {
7+
8+
public init(
9+
object: NSObject,
10+
forKeyPaths keyPaths: [String],
11+
context: UnsafeMutableRawPointer?
12+
) {
913
self.object = object
1014
self.keyPaths = keyPaths
1115
super.init()
@@ -19,8 +23,8 @@ final class UserDefaultsObserver: NSObject {
1923
object?.removeObserver(self, forKeyPath: keyPath)
2024
}
2125
}
22-
23-
override func observeValue(
26+
27+
public override func observeValue(
2428
forKeyPath keyPath: String?,
2529
of object: Any?,
2630
change: [NSKeyValueChangeKey: Any]?,
@@ -29,3 +33,4 @@ final class UserDefaultsObserver: NSObject {
2933
onChange?()
3034
}
3135
}
36+

ExtensionService/AppDelegate.swift

Lines changed: 11 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import ServiceManagement
99
import ServiceUpdateMigration
1010
import SwiftUI
1111
import UpdateChecker
12+
import UserDefaultsObserver
1213
import UserNotifications
1314

1415
let bundleIdentifierBase = Bundle.main
@@ -18,7 +19,11 @@ let serviceIdentifier = bundleIdentifierBase + ".ExtensionService"
1819
@main
1920
class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
2021
let scheduledCleaner = ScheduledCleaner()
21-
private let userDefaultsObserver = UserDefaultsObserver()
22+
private let userDefaultsObserver = UserDefaultsObserver(
23+
object: UserDefaults.shared,
24+
forKeyPaths: [UserDefaultPreferenceKeys().realtimeSuggestionToggle.key],
25+
context: nil
26+
)
2227
private var statusBarItem: NSStatusItem!
2328
private var xpcListener: (NSXPCListener, ServiceDelegate)?
2429
private let updateChecker =
@@ -78,7 +83,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
7883
action: #selector(checkForUpdate),
7984
keyEquivalent: ""
8085
)
81-
86+
8287
let openCopilotForXcode = NSMenuItem(
8388
title: "Open Copilot for Xcode",
8489
action: #selector(openCopilotForXcode),
@@ -110,21 +115,16 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
110115
statusBarMenu.addItem(.separator())
111116
statusBarMenu.addItem(quitItem)
112117

113-
userDefaultsObserver.onChange = { key in
114-
switch key {
115-
case UserDefaultPreferenceKeys().realtimeSuggestionToggle.key:
116-
toggleRealtimeSuggestions.state = UserDefaults.shared
117-
.value(for: \.realtimeSuggestionToggle) ? .on : .off
118-
default:
119-
break
120-
}
118+
userDefaultsObserver.onChange = {
119+
toggleRealtimeSuggestions.state = UserDefaults.shared
120+
.value(for: \.realtimeSuggestionToggle) ? .on : .off
121121
}
122122
}
123123

124124
@objc func quit() {
125125
exit(0)
126126
}
127-
127+
128128
@objc func openCopilotForXcode() {
129129
let task = Process()
130130
if let appPath = locateHostBundleURL(url: Bundle.main.bundleURL)?.absoluteString {
@@ -234,32 +234,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate {
234234
}
235235
}
236236

237-
private class UserDefaultsObserver: NSObject {
238-
var onChange: ((String?) -> Void)?
239-
240-
override func observeValue(
241-
forKeyPath keyPath: String?,
242-
of object: Any?,
243-
change: [NSKeyValueChangeKey: Any]?,
244-
context: UnsafeMutableRawPointer?
245-
) {
246-
onChange?(keyPath)
247-
}
248-
249-
deinit {
250-
removeObserver(self, forKeyPath: UserDefaultPreferenceKeys().realtimeSuggestionToggle.key)
251-
}
252-
253-
override init() {
254-
super.init()
255-
observe(keyPath: UserDefaultPreferenceKeys().realtimeSuggestionToggle.key)
256-
}
257-
258-
private func observe(keyPath: String) {
259-
UserDefaults.shared.addObserver(self, forKeyPath: keyPath, options: .new, context: nil)
260-
}
261-
}
262-
263237
extension NSRunningApplication {
264238
var isUserOfService: Bool {
265239
[

0 commit comments

Comments
 (0)