Skip to content

Commit c439bc7

Browse files
committed
Discard suggestion when cursor moved to another line
1 parent 1b751fe commit c439bc7

File tree

4 files changed

+44
-16
lines changed

4 files changed

+44
-16
lines changed

Core/Sources/Service/RealtimeSuggestionController.swift

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import Foundation
99
import Logger
1010
import Preferences
1111
import QuartzCore
12+
import XcodeInspector
1213

1314
@ServiceActor
1415
public class RealtimeSuggestionController {
@@ -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 {
@@ -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,14 @@ public class RealtimeSuggestionController {
139137
case kAXValueChangedNotification:
140138
self.triggerPrefetchDebounced()
141139
await self.notifyEditingFileChange(editor: focusElement)
140+
case kAXSelectedTextChangedNotification:
141+
guard let editor = sourceEditor else { continue }
142+
let sourceEditor = SourceEditor(
143+
runningApplication: activeXcode,
144+
element: editor
145+
)
146+
await PseudoCommandHandler()
147+
.invalidateRealtimeSuggestionsIfNeeded(sourceEditor: sourceEditor)
142148
default:
143149
continue
144150
}
@@ -177,13 +183,6 @@ public class RealtimeSuggestionController {
177183

178184
let keycode = Int(event.getIntegerValueField(.keyboardEventKeycode))
179185
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-
}
187186

188187
// Escape should cancel in-flight tasks.
189188
// Except that when the completion panel is presented, it should trigger prefetch instead.

Core/Sources/Service/SuggestionCommandHandler/PseudoCommandHandler.swift

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import ActiveApplicationMonitor
22
import AppKit
3-
import SuggestionModel
43
import Environment
54
import Preferences
65
import SuggestionInjector
6+
import SuggestionModel
7+
import XcodeInspector
78
import XPCShared
89

910
/// It's used to run some commands without really triggering the menu bar item.
@@ -54,6 +55,19 @@ struct PseudoCommandHandler {
5455
}
5556
}
5657

58+
func invalidateRealtimeSuggestionsIfNeeded(sourceEditor: SourceEditor) async {
59+
guard let fileURL = try? await Environment.fetchCurrentFileURL(),
60+
let (_, filespace) = try? await Workspace
61+
.fetchOrCreateWorkspaceIfNeeded(fileURL: fileURL) else { return }
62+
63+
if await !filespace.validateSuggestions(
64+
lines: sourceEditor.content.lines,
65+
cursorPosition: sourceEditor.content.cursorPosition
66+
) {
67+
PresentInWindowSuggestionPresenter().discardSuggestion(fileURL: fileURL)
68+
}
69+
}
70+
5771
func rejectSuggestions() async {
5872
let handler = WindowBaseCommandHandler()
5973
_ = try? await handler.rejectSuggestion(editor: .init(
@@ -214,7 +228,7 @@ extension PseudoCommandHandler {
214228
let content = focusElement.value
215229
let split = content.breakLines()
216230
let range = convertRangeToCursorRange(selectionRange, in: content)
217-
return (content, split, [range], range.end)
231+
return (content, split, [range], range.start)
218232
}
219233

220234
func getFileURL() async -> URL? {
@@ -289,10 +303,10 @@ extension PseudoCommandHandler {
289303
var countE = 0
290304
var cursorRange = CursorRange(start: .zero, end: .outOfScope)
291305
for (i, line) in lines.enumerated() {
292-
if countS <= range.lowerBound && range.lowerBound < countS + line.count {
306+
if countS <= range.lowerBound, range.lowerBound < countS + line.count {
293307
cursorRange.start = .init(line: i, character: range.lowerBound - countS)
294308
}
295-
if countE <= range.upperBound && range.upperBound < countE + line.count {
309+
if countE <= range.upperBound, range.upperBound < countE + line.count {
296310
cursorRange.end = .init(line: i, character: range.upperBound - countE)
297311
break
298312
}
@@ -321,3 +335,4 @@ public extension String {
321335
return all
322336
}
323337
}
338+

Core/Sources/Service/Workspace.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,20 @@ final class Filespace {
6767
func refreshUpdateTime() {
6868
lastSuggestionUpdateTime = Environment.now()
6969
}
70+
71+
func validateSuggestions(lines: [String], cursorPosition: CursorPosition) -> Bool {
72+
if cursorPosition.line != suggestionSourceSnapshot.cursorPosition.line {
73+
reset()
74+
return false
75+
}
76+
77+
guard cursorPosition.line >= 0, cursorPosition.line < lines.count else {
78+
reset()
79+
return false
80+
}
81+
82+
return true
83+
}
7084
}
7185

7286
// MARK: - Workspace

Core/Sources/XcodeInspector/SourceEditor.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class SourceEditor {
3434
content: content,
3535
lines: split,
3636
selections: [range],
37-
cursorPosition: range.end,
37+
cursorPosition: range.start,
3838
lineAnnotations: lineAnnotations
3939
)
4040
}

0 commit comments

Comments
 (0)