@@ -31,12 +31,12 @@ public actor RealtimeSuggestionController {
3131
3232 private func observeXcodeChange( ) {
3333 cancellable. forEach { $0. cancel ( ) }
34-
34+
3535 XcodeInspector . shared. $focusedEditor
3636 . sink { [ weak self] editor in
3737 guard let self else { return }
3838 Task {
39- guard let editor else { return }
39+ guard let editor else { return }
4040 await self . handleFocusElementChange ( editor)
4141 }
4242 } . store ( in: & cancellable)
@@ -51,7 +51,7 @@ public actor RealtimeSuggestionController {
5151 }
5252
5353 self . sourceEditor = sourceEditor
54-
54+
5555 let notificationsFromEditor = sourceEditor. axNotifications
5656
5757 editorObservationTask? . cancel ( )
@@ -65,25 +65,54 @@ public actor RealtimeSuggestionController {
6565 )
6666 }
6767
68- for await notification in notificationsFromEditor {
69- guard let self else { return }
70- try Task . checkCancellation ( )
71-
72- switch notification. kind {
73- case . valueChanged:
74- await cancelInFlightTasks ( )
75- await self . triggerPrefetchDebounced ( )
76- await self . notifyEditingFileChange ( editor: sourceEditor. element)
77- case . selectedTextChanged:
78- guard let fileURL = XcodeInspector . shared. activeDocumentURL
79- else { break }
80- await PseudoCommandHandler ( ) . invalidateRealtimeSuggestionsIfNeeded (
81- fileURL: fileURL,
82- sourceEditor: sourceEditor
83- )
84- default :
85- break
68+ let valueChange = notificationsFromEditor. filter { $0. kind == . valueChanged }
69+ let selectedTextChanged = notificationsFromEditor
70+ . filter { $0. kind == . selectedTextChanged }
71+
72+ await withTaskGroup ( of: Void . self) { [ weak self] group in
73+ group. addTask { [ weak self] in
74+ let handler = { [ weak self] in
75+ guard let self else { return }
76+ await cancelInFlightTasks ( )
77+ await self . triggerPrefetchDebounced ( )
78+ await self . notifyEditingFileChange ( editor: sourceEditor. element)
79+ }
80+
81+ if #available( macOS 13 . 0 , * ) {
82+ for await _ in valueChange. throttle ( for: . milliseconds( 200 ) ) {
83+ if Task . isCancelled { return }
84+ await handler ( )
85+ }
86+ } else {
87+ for await _ in valueChange {
88+ if Task . isCancelled { return }
89+ await handler ( )
90+ }
91+ }
8692 }
93+ group. addTask {
94+ let handler = {
95+ guard let fileURL = XcodeInspector . shared. activeDocumentURL else { return }
96+ await PseudoCommandHandler ( ) . invalidateRealtimeSuggestionsIfNeeded (
97+ fileURL: fileURL,
98+ sourceEditor: sourceEditor
99+ )
100+ }
101+
102+ if #available( macOS 13 . 0 , * ) {
103+ for await _ in selectedTextChanged. throttle ( for: . milliseconds( 200 ) ) {
104+ if Task . isCancelled { return }
105+ await handler ( )
106+ }
107+ } else {
108+ for await _ in selectedTextChanged {
109+ if Task . isCancelled { return }
110+ await handler ( )
111+ }
112+ }
113+ }
114+
115+ await group. waitForAll ( )
87116 }
88117 }
89118
@@ -94,7 +123,7 @@ public actor RealtimeSuggestionController {
94123 . fetchOrCreateWorkspaceAndFilespace ( fileURL: fileURL)
95124
96125 if filespace. codeMetadata. uti == nil {
97- Logger . service. info ( " Generate cache for file. " )
126+ Logger . service. info ( " Generate cache for file. " )
98127 // avoid the command get called twice
99128 filespace. codeMetadata. uti = " "
100129 do {
@@ -111,10 +140,11 @@ public actor RealtimeSuggestionController {
111140
112141 func triggerPrefetchDebounced( force: Bool = false ) {
113142 inflightPrefetchTask = Task ( priority: . utility) { @WorkspaceActor in
114- try ? await Task . sleep ( nanoseconds: UInt64 ( (
143+ try ? await Task . sleep ( nanoseconds: UInt64 (
115144 max ( UserDefaults . shared. value ( for: \. realtimeSuggestionDebounce) , 0.15 )
116- ) * 1_000_000_000 ) )
117-
145+ * 1_000_000_000
146+ ) )
147+
118148 if Task . isCancelled { return }
119149
120150 guard UserDefaults . shared. value ( for: \. realtimeSuggestionToggle)
0 commit comments