@@ -54,6 +54,25 @@ final class Filespace {
5454
5555@ServiceActor
5656final class Workspace {
57+ class UserDefaultsObserver : NSObject {
58+ var onChange : ( ( ) -> Void ) ?
59+
60+ override func observeValue(
61+ forKeyPath keyPath: String ? ,
62+ of object: Any ? ,
63+ change: [ NSKeyValueChangeKey : Any ] ? ,
64+ context: UnsafeMutableRawPointer ?
65+ ) {
66+ onChange ? ( )
67+ }
68+ }
69+
70+ struct SuggestionFeatureDisabledError : Error , LocalizedError {
71+ var errorDescription : String ? {
72+ " Suggestion feature is disabled for this project. "
73+ }
74+ }
75+
5776 let projectRootURL : URL
5877 var lastTriggerDate = Environment . now ( )
5978 var isExpired : Bool {
@@ -66,12 +85,56 @@ final class Workspace {
6685 }
6786
6887 var realtimeSuggestionRequests = Set < Task < Void , Error > > ( )
88+ let userDefaultsObserver = UserDefaultsObserver ( )
89+
90+ private var _copilotSuggestionService : CopilotSuggestionServiceType ?
91+
92+ private var copilotSuggestionService : CopilotSuggestionServiceType ? {
93+ // Check if the workspace is disabled.
94+ let isSuggestionDisabledGlobally = UserDefaults . shared
95+ . value ( for: \. disableSuggestionFeatureGlobally)
96+ if isSuggestionDisabledGlobally {
97+ let enabledList = UserDefaults . shared. value ( for: \. suggestionFeatureEnabledProjectList)
98+ if !enabledList. contains ( where: { path in projectRootURL. path. hasPrefix ( path) } ) {
99+ // If it's disable, remove the service
100+ _copilotSuggestionService = nil
101+ return nil
102+ }
103+ }
69104
70- private lazy var service : CopilotSuggestionServiceType = Environment
71- . createSuggestionService ( projectRootURL)
105+ if _copilotSuggestionService == nil {
106+ _copilotSuggestionService = Environment . createSuggestionService ( projectRootURL)
107+ }
108+ return _copilotSuggestionService
109+ }
110+
111+ var isSuggestionFeatureEnabled : Bool {
112+ copilotSuggestionService != nil
113+ }
72114
73- init ( projectRootURL: URL ) {
115+ private init ( projectRootURL: URL ) {
74116 self . projectRootURL = projectRootURL
117+
118+ Task {
119+ userDefaultsObserver. onChange = { [ weak self] in
120+ guard let self else { return }
121+ _ = self . copilotSuggestionService
122+ }
123+
124+ UserDefaults . shared. addObserver (
125+ userDefaultsObserver,
126+ forKeyPath: UserDefaultPreferenceKeys ( ) . suggestionFeatureEnabledProjectList. key,
127+ options: . new,
128+ context: nil
129+ )
130+
131+ UserDefaults . shared. addObserver (
132+ userDefaultsObserver,
133+ forKeyPath: UserDefaultPreferenceKeys ( ) . disableSuggestionFeatureGlobally. key,
134+ options: . new,
135+ context: nil
136+ )
137+ }
75138 }
76139
77140 func canAutoTriggerGetSuggestions(
@@ -132,7 +195,8 @@ extension Workspace {
132195
133196 filespace. suggestionSourceSnapshot = snapshot
134197
135- let completions = try await service. getCompletions (
198+ guard let copilotSuggestionService else { throw SuggestionFeatureDisabledError ( ) }
199+ let completions = try await copilotSuggestionService. getCompletions (
136200 fileURL: fileURL,
137201 content: editor. lines. joined ( separator: " " ) ,
138202 cursorPosition: editor. cursorPosition,
@@ -183,7 +247,7 @@ extension Workspace {
183247 filespaces [ fileURL] ? . usesTabsForIndentation = editor. usesTabsForIndentation
184248 }
185249 Task {
186- await service . notifyRejected ( filespaces [ fileURL] ? . suggestions ?? [ ] )
250+ await copilotSuggestionService ? . notifyRejected ( filespaces [ fileURL] ? . suggestions ?? [ ] )
187251 }
188252 filespaces [ fileURL] ? . reset ( resetSnapshot: false )
189253 }
@@ -208,8 +272,8 @@ extension Workspace {
208272 let suggestion = allSuggestions. remove ( at: filespace. suggestionIndex)
209273
210274 Task {
211- await service . notifyAccepted ( suggestion)
212- await service . notifyRejected ( allSuggestions)
275+ await copilotSuggestionService ? . notifyAccepted ( suggestion)
276+ await copilotSuggestionService ? . notifyRejected ( allSuggestions)
213277 }
214278
215279 filespaces [ fileURL] ? . reset ( )
0 commit comments