Skip to content

Commit a464a49

Browse files
committed
Handle source editor AXNotifications in SourceEditor
1 parent 930780f commit a464a49

1 file changed

Lines changed: 71 additions & 16 deletions

File tree

Tool/Sources/XcodeInspector/SourceEditor.swift

Lines changed: 71 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import AppKit
2+
import AsyncExtensions
23
import AXNotificationStream
34
import Foundation
45
import SuggestionModel
@@ -7,8 +8,21 @@ import SuggestionModel
78
public class SourceEditor {
89
public typealias Content = EditorInformation.SourceEditorContent
910

11+
public struct AXNotification {
12+
public var kind: AXNotificationKind
13+
public var element: AXUIElement
14+
}
15+
16+
public enum AXNotificationKind {
17+
case selectedTextChanged
18+
case valueChanged
19+
case scrollPositionChanged
20+
}
21+
22+
public let axNotifications = AsyncPassthroughSubject<AXNotification>()
1023
let runningApplication: NSRunningApplication
1124
public let element: AXUIElement
25+
var observeAXNotificationsTask: Task<Void, Never>?
1226

1327
/// The content of the source editor.
1428
public var content: Content {
@@ -39,25 +53,66 @@ public class SourceEditor {
3953
public init(runningApplication: NSRunningApplication, element: AXUIElement) {
4054
self.runningApplication = runningApplication
4155
self.element = element
42-
}
4356

44-
/// Observe to changes in the source editor.
45-
public func observe(notificationNames: String...) -> AXNotificationStream {
46-
return AXNotificationStream(
47-
app: runningApplication,
48-
element: element,
49-
notificationNames: notificationNames
50-
)
57+
Task { @MainActor in
58+
observeAXNotifications()
59+
}
5160
}
5261

53-
/// Observe to changes in the source editor scroll view.
54-
public func observeScrollView(notificationNames: String...) -> AXNotificationStream? {
55-
guard let scrollView = element.parent else { return nil }
56-
return AXNotificationStream(
57-
app: runningApplication,
58-
element: scrollView,
59-
notificationNames: notificationNames
60-
)
62+
@MainActor
63+
func observeAXNotifications() {
64+
observeAXNotificationsTask?.cancel()
65+
observeAXNotificationsTask = Task { @MainActor [weak self] in
66+
guard let self else { return }
67+
await withTaskGroup(of: Void.self) { [weak self] group in
68+
guard let self else { return }
69+
let editorNotifications = AXNotificationStream(
70+
app: runningApplication,
71+
element: element,
72+
notificationNames:
73+
kAXSelectedTextChangedNotification,
74+
kAXValueChangedNotification
75+
)
76+
77+
group.addTask { [weak self] in
78+
for await notification in editorNotifications {
79+
guard let self else { return }
80+
if let kind: AXNotificationKind = {
81+
switch notification.name {
82+
case kAXSelectedTextChangedNotification: return .selectedTextChanged
83+
case kAXValueChangedNotification: return .valueChanged
84+
default: return nil
85+
}
86+
}() {
87+
self.axNotifications.send(.init(
88+
kind: kind,
89+
element: notification.element
90+
))
91+
}
92+
}
93+
}
94+
95+
if let scrollView = element.parent, let scrollBar = scrollView.verticalScrollBar {
96+
let scrollViewNotifications = AXNotificationStream(
97+
app: runningApplication,
98+
element: scrollBar,
99+
notificationNames: kAXValueChangedNotification
100+
)
101+
102+
group.addTask { [weak self] in
103+
for await notification in scrollViewNotifications {
104+
guard let self else { return }
105+
self.axNotifications.send(.init(
106+
kind: .scrollPositionChanged,
107+
element: notification.element
108+
))
109+
}
110+
}
111+
}
112+
113+
await group.waitForAll()
114+
}
115+
}
61116
}
62117
}
63118

0 commit comments

Comments
 (0)