Skip to content

Commit 9bee878

Browse files
committed
Access XcodeInspector thru actor
1 parent 0266337 commit 9bee878

File tree

14 files changed

+102
-69
lines changed

14 files changed

+102
-69
lines changed

Core/Sources/ChatPlugin/TerminalChatPlugin.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ public actor TerminalChatPlugin: ChatPlugin {
3434
}
3535

3636
do {
37-
let fileURL = XcodeInspector.shared.realtimeActiveDocumentURL
38-
let projectURL = XcodeInspector.shared.realtimeActiveProjectURL
37+
let fileURL = await XcodeInspector.shared.safe.realtimeActiveDocumentURL
38+
let projectURL = await XcodeInspector.shared.safe.realtimeActiveProjectURL
3939

4040
var environment = [String: String]()
4141
if let fileURL {

Core/Sources/ChatService/ChatService.swift

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,14 @@ public final class ChatService: ObservableObject {
217217
guard let info else { return }
218218

219219
let templateProcessor = CustomCommandTemplateProcessor()
220-
mutateSystemPrompt(info.specifiedSystemPrompt.map(templateProcessor.process))
221-
mutateExtraSystemPrompt(info.extraSystemPrompt.map(templateProcessor.process) ?? "")
220+
if let specifiedSystemPrompt = info.specifiedSystemPrompt {
221+
await mutateSystemPrompt(templateProcessor.process(specifiedSystemPrompt))
222+
}
223+
if let extraSystemPrompt = info.extraSystemPrompt {
224+
await mutateExtraSystemPrompt(templateProcessor.process(extraSystemPrompt))
225+
} else {
226+
mutateExtraSystemPrompt("")
227+
}
222228

223229
let customCommandPrefix = {
224230
if let name = info.name { return "[\(name)] " }
@@ -250,9 +256,9 @@ public final class ChatService: ObservableObject {
250256
let templateProcessor = CustomCommandTemplateProcessor()
251257
if let systemPrompt {
252258
if overwriteSystemPrompt {
253-
mutateSystemPrompt(templateProcessor.process(systemPrompt))
259+
await mutateSystemPrompt(templateProcessor.process(systemPrompt))
254260
} else {
255-
mutateExtraSystemPrompt(templateProcessor.process(systemPrompt))
261+
await mutateExtraSystemPrompt(templateProcessor.process(systemPrompt))
256262
}
257263
}
258264
return try await sendAndWait(content: templateProcessor.process(prompt))
@@ -265,10 +271,10 @@ public final class ChatService: ObservableObject {
265271
) async throws -> String {
266272
let templateProcessor = CustomCommandTemplateProcessor()
267273
if let systemPrompt {
268-
mutateSystemPrompt(templateProcessor.process(systemPrompt))
274+
await mutateSystemPrompt(templateProcessor.process(systemPrompt))
269275
}
270276
if let extraSystemPrompt {
271-
mutateExtraSystemPrompt(templateProcessor.process(extraSystemPrompt))
277+
await mutateExtraSystemPrompt(templateProcessor.process(extraSystemPrompt))
272278
}
273279
return try await sendAndWait(content: templateProcessor.process(prompt))
274280
}

Core/Sources/ChatService/CustomCommandTemplateProcessor.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ import XcodeInspector
66
public struct CustomCommandTemplateProcessor {
77
public init() {}
88

9-
public func process(_ text: String) -> String {
10-
let info = getEditorInformation()
9+
public func process(_ text: String) async -> String {
10+
let info = await getEditorInformation()
1111
let editorContent = info.editorContent
1212
let updatedText = text
1313
.replacingOccurrences(of: "{{selected_code}}", with: """
@@ -38,9 +38,9 @@ public struct CustomCommandTemplateProcessor {
3838
let documentURL: URL?
3939
}
4040

41-
func getEditorInformation() -> EditorInformation {
42-
let editorContent = XcodeInspector.shared.focusedEditor?.getContent()
43-
let documentURL = XcodeInspector.shared.activeDocumentURL
41+
func getEditorInformation() async -> EditorInformation {
42+
let editorContent = await XcodeInspector.shared.safe.focusedEditor?.getContent()
43+
let documentURL = await XcodeInspector.shared.safe.activeDocumentURL
4444
let language = documentURL.map(languageIdentifierFromFileURL) ?? .plaintext
4545

4646
return .init(

Core/Sources/PromptToCodeService/OpenAIPromptToCodeService.swift

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,23 @@ public final class OpenAIPromptToCodeService: PromptToCodeServiceType {
3131
return userPreferredLanguage.isEmpty ? "" : " in \(userPreferredLanguage)"
3232
}()
3333

34-
let editor: EditorInformation = await XcodeInspector.shared.getFocusedEditorContent() ?? .init(
35-
editorContent: .init(
36-
content: source.content,
37-
lines: source.lines,
38-
selections: [source.range],
39-
cursorPosition: .outOfScope,
40-
lineAnnotations: []
41-
),
42-
selectedContent: code,
43-
selectedLines: [],
44-
documentURL: source.documentURL,
45-
workspaceURL: source.projectRootURL,
46-
projectRootURL: source.projectRootURL,
47-
relativePath: "",
48-
language: source.language
49-
)
34+
let editor: EditorInformation = await XcodeInspector.shared.getFocusedEditorContent()
35+
?? .init(
36+
editorContent: .init(
37+
content: source.content,
38+
lines: source.lines,
39+
selections: [source.range],
40+
cursorPosition: .outOfScope,
41+
lineAnnotations: []
42+
),
43+
selectedContent: code,
44+
selectedLines: [],
45+
documentURL: source.documentURL,
46+
workspaceURL: source.projectRootURL,
47+
projectRootURL: source.projectRootURL,
48+
relativePath: "",
49+
language: source.language
50+
)
5051

5152
let rule: String = {
5253
func generateDescription(index: Int) -> String {

Core/Sources/Service/RealtimeSuggestionController.swift

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,8 @@ public actor RealtimeSuggestionController {
4545
private func handleFocusElementChange(_ sourceEditor: SourceEditor) {
4646
Task { // Notify suggestion service for open file.
4747
try await Task.sleep(nanoseconds: 500_000_000)
48-
guard let fileURL = XcodeInspector.shared.realtimeActiveDocumentURL else { return }
48+
guard let fileURL = await XcodeInspector.shared.safe.realtimeActiveDocumentURL
49+
else { return }
4950
_ = try await Service.shared.workspacePool
5051
.fetchOrCreateWorkspaceAndFilespace(fileURL: fileURL)
5152
}
@@ -58,7 +59,7 @@ public actor RealtimeSuggestionController {
5859
editorObservationTask = nil
5960

6061
editorObservationTask = Task { [weak self] in
61-
if let fileURL = XcodeInspector.shared.realtimeActiveDocumentURL {
62+
if let fileURL = await XcodeInspector.shared.safe.realtimeActiveDocumentURL {
6263
await PseudoCommandHandler().invalidateRealtimeSuggestionsIfNeeded(
6364
fileURL: fileURL,
6465
sourceEditor: sourceEditor
@@ -93,7 +94,8 @@ public actor RealtimeSuggestionController {
9394
}
9495
group.addTask {
9596
let handler = {
96-
guard let fileURL = XcodeInspector.shared.activeDocumentURL else { return }
97+
guard let fileURL = await XcodeInspector.shared.safe.activeDocumentURL
98+
else { return }
9799
await PseudoCommandHandler().invalidateRealtimeSuggestionsIfNeeded(
98100
fileURL: fileURL,
99101
sourceEditor: sourceEditor
@@ -119,7 +121,8 @@ public actor RealtimeSuggestionController {
119121

120122
Task { @WorkspaceActor in // Get cache ready for real-time suggestions.
121123
guard UserDefaults.shared.value(for: \.preCacheOnFileOpen) else { return }
122-
guard let fileURL = XcodeInspector.shared.realtimeActiveDocumentURL else { return }
124+
guard let fileURL = await XcodeInspector.shared.safe.realtimeActiveDocumentURL
125+
else { return }
123126
let (_, filespace) = try await Service.shared.workspacePool
124127
.fetchOrCreateWorkspaceAndFilespace(fileURL: fileURL)
125128

@@ -128,7 +131,7 @@ public actor RealtimeSuggestionController {
128131
// avoid the command get called twice
129132
filespace.codeMetadata.uti = ""
130133
do {
131-
try await XcodeInspector.shared.latestActiveXcode?
134+
try await XcodeInspector.shared.safe.latestActiveXcode?
132135
.triggerCopilotCommand(name: "Real-time Suggestions")
133136
} catch {
134137
if filespace.codeMetadata.uti?.isEmpty ?? true {
@@ -152,7 +155,7 @@ public actor RealtimeSuggestionController {
152155
else { return }
153156

154157
if UserDefaults.shared.value(for: \.disableSuggestionFeatureGlobally),
155-
let fileURL = XcodeInspector.shared.activeDocumentURL,
158+
let fileURL = await XcodeInspector.shared.safe.activeDocumentURL,
156159
let (workspace, _) = try? await Service.shared.workspacePool
157160
.fetchOrCreateWorkspaceAndFilespace(fileURL: fileURL)
158161
{
@@ -189,7 +192,7 @@ public actor RealtimeSuggestionController {
189192
}
190193

191194
func notifyEditingFileChange(editor: AXUIElement) async {
192-
guard let fileURL = XcodeInspector.shared.activeDocumentURL,
195+
guard let fileURL = await XcodeInspector.shared.safe.activeDocumentURL,
193196
let (workspace, _) = try? await Service.shared.workspacePool
194197
.fetchOrCreateWorkspaceAndFilespace(fileURL: fileURL)
195198
else { return }

Core/Sources/Service/SuggestionCommandHandler/PseudoCommandHandler.swift

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ struct PseudoCommandHandler {
159159
}
160160
}() else {
161161
do {
162-
try await XcodeInspector.shared.latestActiveXcode?
162+
try await XcodeInspector.shared.safe.latestActiveXcode?
163163
.triggerCopilotCommand(name: command.name)
164164
} catch {
165165
let presenter = PresentInWindowSuggestionPresenter()
@@ -183,7 +183,7 @@ struct PseudoCommandHandler {
183183
throw CancellationError()
184184
}
185185
do {
186-
try await XcodeInspector.shared.latestActiveXcode?
186+
try await XcodeInspector.shared.safe.latestActiveXcode?
187187
.triggerCopilotCommand(name: "Accept Prompt to Code")
188188
} catch {
189189
let last = Self.lastTimeCommandFailedToTriggerWithAccessibilityAPI
@@ -238,7 +238,7 @@ struct PseudoCommandHandler {
238238
throw CancellationError()
239239
}
240240
do {
241-
try await XcodeInspector.shared.latestActiveXcode?
241+
try await XcodeInspector.shared.safe.latestActiveXcode?
242242
.triggerCopilotCommand(name: "Accept Suggestion")
243243
} catch {
244244
let last = Self.lastTimeCommandFailedToTriggerWithAccessibilityAPI
@@ -288,7 +288,7 @@ struct PseudoCommandHandler {
288288
}
289289

290290
func dismissSuggestion() async {
291-
guard let documentURL = XcodeInspector.shared.activeDocumentURL else { return }
291+
guard let documentURL = await XcodeInspector.shared.safe.activeDocumentURL else { return }
292292
guard let (_, filespace) = try? await Service.shared.workspacePool
293293
.fetchOrCreateWorkspaceAndFilespace(fileURL: documentURL) else { return }
294294

@@ -377,14 +377,14 @@ extension PseudoCommandHandler {
377377
return (content, split, [range], range.start)
378378
}
379379

380-
func getFileURL() -> URL? {
381-
XcodeInspector.shared.realtimeActiveDocumentURL
380+
func getFileURL() async -> URL? {
381+
await XcodeInspector.shared.safe.realtimeActiveDocumentURL
382382
}
383383

384384
@WorkspaceActor
385385
func getFilespace() async -> Filespace? {
386386
guard
387-
let fileURL = getFileURL(),
387+
let fileURL = await getFileURL(),
388388
let (_, filespace) = try? await Service.shared.workspacePool
389389
.fetchOrCreateWorkspaceAndFilespace(fileURL: fileURL)
390390
else { return nil }
@@ -394,7 +394,10 @@ extension PseudoCommandHandler {
394394
@WorkspaceActor
395395
func getEditorContent(sourceEditor: SourceEditor?) async -> EditorContent? {
396396
guard let filespace = await getFilespace(),
397-
let sourceEditor = sourceEditor ?? XcodeInspector.shared.focusedEditor
397+
let sourceEditor = await {
398+
if let sourceEditor { sourceEditor }
399+
else { await XcodeInspector.shared.safe.focusedEditor }
400+
}()
398401
else { return nil }
399402
if Task.isCancelled { return nil }
400403
let content = sourceEditor.getContent()

Core/Sources/Service/SuggestionCommandHandler/WindowBaseCommandHandler.swift

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ struct WindowBaseCommandHandler: SuggestionCommandHandler {
3939
defer {
4040
presenter.markAsProcessing(false)
4141
}
42-
guard let fileURL = XcodeInspector.shared.realtimeActiveDocumentURL else { return }
42+
guard let fileURL = await XcodeInspector.shared.safe.realtimeActiveDocumentURL
43+
else { return }
4344
let (workspace, filespace) = try await Service.shared.workspacePool
4445
.fetchOrCreateWorkspaceAndFilespace(fileURL: fileURL)
4546

@@ -80,7 +81,8 @@ struct WindowBaseCommandHandler: SuggestionCommandHandler {
8081

8182
@WorkspaceActor
8283
private func _presentNextSuggestion(editor: EditorContent) async throws {
83-
guard let fileURL = XcodeInspector.shared.realtimeActiveDocumentURL else { return }
84+
guard let fileURL = await XcodeInspector.shared.safe.realtimeActiveDocumentURL
85+
else { return }
8486
let (workspace, filespace) = try await Service.shared.workspacePool
8587
.fetchOrCreateWorkspaceAndFilespace(fileURL: fileURL)
8688
workspace.selectNextSuggestion(forFileAt: fileURL)
@@ -105,7 +107,8 @@ struct WindowBaseCommandHandler: SuggestionCommandHandler {
105107

106108
@WorkspaceActor
107109
private func _presentPreviousSuggestion(editor: EditorContent) async throws {
108-
guard let fileURL = XcodeInspector.shared.realtimeActiveDocumentURL else { return }
110+
guard let fileURL = await XcodeInspector.shared.safe.realtimeActiveDocumentURL
111+
else { return }
109112
let (workspace, filespace) = try await Service.shared.workspacePool
110113
.fetchOrCreateWorkspaceAndFilespace(fileURL: fileURL)
111114
workspace.selectPreviousSuggestion(forFileAt: fileURL)
@@ -130,7 +133,8 @@ struct WindowBaseCommandHandler: SuggestionCommandHandler {
130133

131134
@WorkspaceActor
132135
private func _rejectSuggestion(editor: EditorContent) async throws {
133-
guard let fileURL = XcodeInspector.shared.realtimeActiveDocumentURL else { return }
136+
guard let fileURL = await XcodeInspector.shared.safe.realtimeActiveDocumentURL
137+
else { return }
134138

135139
let (workspace, _) = try await Service.shared.workspacePool
136140
.fetchOrCreateWorkspaceAndFilespace(fileURL: fileURL)
@@ -140,7 +144,8 @@ struct WindowBaseCommandHandler: SuggestionCommandHandler {
140144

141145
@WorkspaceActor
142146
func acceptSuggestion(editor: EditorContent) async throws -> UpdatedContent? {
143-
guard let fileURL = XcodeInspector.shared.realtimeActiveDocumentURL else { return nil }
147+
guard let fileURL = await XcodeInspector.shared.safe.realtimeActiveDocumentURL
148+
else { return nil }
144149
let (workspace, _) = try await Service.shared.workspacePool
145150
.fetchOrCreateWorkspaceAndFilespace(fileURL: fileURL)
146151

@@ -173,7 +178,8 @@ struct WindowBaseCommandHandler: SuggestionCommandHandler {
173178
}
174179

175180
func acceptPromptToCode(editor: EditorContent) async throws -> UpdatedContent? {
176-
guard let fileURL = XcodeInspector.shared.realtimeActiveDocumentURL else { return nil }
181+
guard let fileURL = await XcodeInspector.shared.safe.realtimeActiveDocumentURL
182+
else { return nil }
177183

178184
let injector = SuggestionInjector()
179185
var lines = editor.lines
@@ -248,7 +254,8 @@ struct WindowBaseCommandHandler: SuggestionCommandHandler {
248254

249255
@WorkspaceActor
250256
func prepareCache(editor: EditorContent) async throws -> UpdatedContent? {
251-
guard let fileURL = XcodeInspector.shared.realtimeActiveDocumentURL else { return nil }
257+
guard let fileURL = await XcodeInspector.shared.safe.realtimeActiveDocumentURL
258+
else { return nil }
252259
let (_, filespace) = try await Service.shared.workspacePool
253260
.fetchOrCreateWorkspaceAndFilespace(fileURL: fileURL)
254261
filespace.codeMetadata.uti = editor.uti
@@ -351,7 +358,8 @@ extension WindowBaseCommandHandler {
351358
generateDescription: Bool?,
352359
name: String?
353360
) async throws {
354-
guard let fileURL = XcodeInspector.shared.realtimeActiveDocumentURL else { return }
361+
guard let fileURL = await XcodeInspector.shared.safe.realtimeActiveDocumentURL
362+
else { return }
355363
let (workspace, filespace) = try await Service.shared.workspacePool
356364
.fetchOrCreateWorkspaceAndFilespace(fileURL: fileURL)
357365
guard workspace.suggestionPlugin?.isSuggestionFeatureEnabled ?? false else {
@@ -398,8 +406,18 @@ extension WindowBaseCommandHandler {
398406
let viewStore = Service.shared.guiController.viewStore
399407

400408
let customCommandTemplateProcessor = CustomCommandTemplateProcessor()
401-
let newExtraSystemPrompt = extraSystemPrompt.map(customCommandTemplateProcessor.process)
402-
let newPrompt = prompt.map(customCommandTemplateProcessor.process)
409+
410+
let newExtraSystemPrompt: String? = if let extraSystemPrompt {
411+
await customCommandTemplateProcessor.process(extraSystemPrompt)
412+
} else {
413+
nil
414+
}
415+
416+
let newPrompt: String? = if let prompt {
417+
await customCommandTemplateProcessor.process(prompt)
418+
} else {
419+
nil
420+
}
403421

404422
_ = await Task { @MainActor in
405423
// if there is already a prompt to code presenting, we should not present another one

Core/Sources/SuggestionWidget/FeatureReducers/PanelFeature.swift

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ public struct PanelFeature: ReducerProtocol {
5353
switch action {
5454
case .presentSuggestion:
5555
return .run { send in
56-
guard let fileURL = xcodeInspector.activeDocumentURL,
56+
guard let fileURL = await xcodeInspector.safe.activeDocumentURL,
5757
let provider = await fetchSuggestionProvider(fileURL: fileURL)
5858
else { return }
5959
await send(.presentSuggestionProvider(provider, displayContent: true))
@@ -98,8 +98,9 @@ public struct PanelFeature: ReducerProtocol {
9898
state.content.error = nil
9999
state.content.suggestion = nil
100100
return .run { send in
101-
guard let fileURL = xcodeInspector.realtimeActiveDocumentURL else { return }
102-
101+
guard let fileURL = await xcodeInspector.safe.realtimeActiveDocumentURL
102+
else { return }
103+
103104
await send(.sharedPanel(
104105
.promptToCodeGroup(
105106
.updateActivePromptToCode(documentURL: fileURL)

Core/Sources/SuggestionWidget/FeatureReducers/WidgetFeature.swift

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -293,12 +293,11 @@ public struct WidgetFeature: ReducerProtocol {
293293
}.cancellable(id: CancelID.observeUserDefaults, cancelInFlight: true)
294294

295295
case .updateActiveApplication:
296-
if let app = xcodeInspector.activeApplication, app.isXcode {
297-
return .run { send in
296+
return .run { send in
297+
if let app = await xcodeInspector.safe.activeApplication, app.isXcode {
298298
await send(.panel(.switchToAnotherEditorAndUpdateContent))
299299
}
300300
}
301-
return .none
302301

303302
case .updateColorScheme:
304303
let widgetColorScheme = UserDefaults.shared.value(for: \.widgetColorScheme)

0 commit comments

Comments
 (0)