Skip to content

Commit 1d5aac7

Browse files
committed
Indicator follows the editing cursor if possible
1 parent d5298f2 commit 1d5aac7

File tree

4 files changed

+45
-4
lines changed

4 files changed

+45
-4
lines changed

Core/Sources/Service/Environment.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,4 +204,13 @@ extension AXUIElement {
204204
}
205205
throw error
206206
}
207+
208+
func copyParameterizedValue<T>(key: String, parameters: AnyObject, ofType _: T.Type = T.self) throws -> T {
209+
var value: AnyObject?
210+
let error = AXUIElementCopyParameterizedAttributeValue(self, key as CFString, parameters as CFTypeRef, &value)
211+
if error == .success, let value = value as? T {
212+
return value
213+
}
214+
throw error
215+
}
207216
}

Core/Sources/Service/RealtimeSuggestionController.swift

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -173,9 +173,9 @@ final class RealtimeSuggestionIndicatorController {
173173
@ObservedObject var viewModel: IndicatorContentViewModel
174174
@State var progress: CGFloat = 1
175175
var opacityA: CGFloat { progress }
176-
var opacityB: CGFloat { (1 - progress) }
176+
var opacityB: CGFloat { 1 - progress }
177177
var scaleA: CGFloat { progress / 2 + 0.5 }
178-
var scaleB: CGFloat { 1 - progress }
178+
var scaleB: CGFloat { max(1 - progress, 0.01) }
179179

180180
var body: some View {
181181
Circle()
@@ -315,6 +315,36 @@ final class RealtimeSuggestionIndicatorController {
315315
return
316316
}
317317

318+
if let activeXcode = NSRunningApplication
319+
.runningApplications(withBundleIdentifier: "com.apple.dt.Xcode")
320+
.first(where: \.isActive)
321+
{
322+
let application = AXUIElementCreateApplication(activeXcode.processIdentifier)
323+
if let focusElement: AXUIElement = try? application
324+
.copyValue(key: kAXFocusedUIElementAttribute),
325+
let selectedRange: AXValue = try? focusElement
326+
.copyValue(key: kAXSelectedTextRangeAttribute),
327+
let rect: AXValue = try? focusElement.copyParameterizedValue(
328+
key: kAXBoundsForRangeParameterizedAttribute,
329+
parameters: selectedRange
330+
)
331+
{
332+
var frame: CGRect = .zero
333+
let found = AXValueGetValue(rect, .cgRect, &frame)
334+
let screen = NSScreen.screens.first
335+
if found, let screen {
336+
frame.origin = .init(
337+
x: frame.maxX + 5,
338+
y: screen.frame.height - frame.minY - 12
339+
)
340+
frame.size = .init(width: 10, height: 10)
341+
window.setFrame(frame, display: false)
342+
window.makeKey()
343+
return
344+
}
345+
}
346+
}
347+
318348
var frame = window.frame
319349
let location = NSEvent.mouseLocation
320350
frame.origin = .init(x: location.x + 15, y: location.y + 15)

EditorExtension/SourceEditorExtension.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ class SourceEditorExtension: NSObject, XCSourceEditorExtension {
99
RejectSuggestionCommand(),
1010
NextSuggestionCommand(),
1111
PreviousSuggestionCommand(),
12+
TurnOnRealtimeSuggestionsCommand(),
13+
TurnOffRealtimeSuggestionsCommand(),
1214
RealtimeSuggestionsCommand(),
1315
PrefetchSuggestionsCommand(),
1416
].map(makeCommandDefinition)

EditorExtension/TurnOnRealtimeSuggestionsCommand.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import CopilotModel
33
import Foundation
44
import XcodeKit
55

6-
class TurnOnRealtimeSuggestionsCommand: NSObject, XCSourceEditorCommand, CommandType {
7-
var name: String { "Turn On Real-time Suggestions" }
6+
class ToggleRealtimeSuggestionsCommand: NSObject, XCSourceEditorCommand, CommandType {
7+
var name: String { "Toggle Real-time Suggestions" }
88

99
func perform(
1010
with invocation: XCSourceEditorCommandInvocation,

0 commit comments

Comments
 (0)