@@ -9,6 +9,7 @@ import Foundation
99import Logger
1010import Preferences
1111import QuartzCore
12+ import XcodeInspector
1213
1314@ServiceActor
1415public class RealtimeSuggestionController {
@@ -25,7 +26,7 @@ public class RealtimeSuggestionController {
2526 private var activeApplicationMonitorTask : Task < Void , Error > ?
2627 private var editorObservationTask : Task < Void , Error > ?
2728 private var focusedUIElement : AXUIElement ?
28- private var sourceEditor : AXUIElement ?
29+ private var sourceEditor : SourceEditor ?
2930
3031 var isCommentMode : Bool {
3132 UserDefaults . shared. value ( for: \. suggestionPresentationMode) == . comment
@@ -48,9 +49,6 @@ public class RealtimeSuggestionController {
4849 await self . handleXcodeChanged ( app)
4950 }
5051
51- #warning(
52- " TODO: Is it possible to get rid of hid event observation with only AXObserver? "
53- )
5452 if ActiveApplicationMonitor . activeXcode != nil {
5553 await startHIDObservation ( by: 1 )
5654 } else {
@@ -118,7 +116,7 @@ public class RealtimeSuggestionController {
118116 }
119117
120118 guard focusElementType == " Source Editor " else { return }
121- sourceEditor = focusElement
119+ sourceEditor = SourceEditor ( runningApplication : activeXcode , element : focusElement)
122120
123121 editorObservationTask? . cancel ( )
124122 editorObservationTask = nil
@@ -127,7 +125,7 @@ public class RealtimeSuggestionController {
127125 let notificationsFromEditor = AXNotificationStream (
128126 app: activeXcode,
129127 element: focusElement,
130- notificationNames: kAXValueChangedNotification
128+ notificationNames: kAXValueChangedNotification, kAXSelectedTextChangedNotification
131129 )
132130
133131 for await notification in notificationsFromEditor {
@@ -139,6 +137,10 @@ public class RealtimeSuggestionController {
139137 case kAXValueChangedNotification:
140138 self . triggerPrefetchDebounced ( )
141139 await self . notifyEditingFileChange ( editor: focusElement)
140+ case kAXSelectedTextChangedNotification:
141+ guard let sourceEditor else { continue }
142+ await PseudoCommandHandler ( )
143+ . invalidateRealtimeSuggestionsIfNeeded ( sourceEditor: sourceEditor)
142144 default :
143145 continue
144146 }
@@ -169,29 +171,16 @@ public class RealtimeSuggestionController {
169171 func handleHIDEvent( event: CGEvent ) async {
170172 guard await Environment . isXcodeActive ( ) else { return }
171173
172- // Mouse clicks should cancel in-flight tasks.
173- if [ CGEventType . rightMouseDown, . leftMouseDown] . contains ( event. type) {
174- await cancelInFlightTasks ( )
175- return
176- }
177-
178174 let keycode = Int ( event. getIntegerValueField ( . keyboardEventKeycode) )
179175 let escape = 0x35
180- let arrowKeys = [ 0x7B , 0x7C , 0x7D , 0x7E ]
181-
182- // Arrow keys should cancel in-flight tasks.
183- if arrowKeys. contains ( keycode) {
184- await cancelInFlightTasks ( )
185- return
186- }
187176
188177 // Escape should cancel in-flight tasks.
189178 // Except that when the completion panel is presented, it should trigger prefetch instead.
190179 if keycode == escape {
191180 if event. type == . keyDown {
192181 await cancelInFlightTasks ( )
193182 } else {
194- let task = Task {
183+ Task {
195184 #warning(
196185 " TODO: Any method to avoid using AppleScript to check that completion panel is presented? "
197186 )
@@ -200,7 +189,6 @@ public class RealtimeSuggestionController {
200189 self . triggerPrefetchDebounced ( force: true )
201190 }
202191 }
203- inflightRealtimeSuggestionsTasks. insert ( task)
204192 }
205193 }
206194 }
@@ -247,18 +235,6 @@ public class RealtimeSuggestionController {
247235 await workspace. cancelInFlightRealtimeSuggestionRequests ( )
248236 }
249237 }
250- group. addTask {
251- await { @ServiceActor in
252- inflightRealtimeSuggestionsTasks. forEach {
253- if $0 == excluding { return }
254- $0. cancel ( )
255- }
256- inflightRealtimeSuggestionsTasks. removeAll ( )
257- if let excluded = excluding {
258- inflightRealtimeSuggestionsTasks. insert ( excluded)
259- }
260- } ( )
261- }
262238 }
263239 }
264240
0 commit comments