11import AppKit
2+ import AsyncExtensions
23import AXNotificationStream
34import Foundation
45import SuggestionModel
@@ -7,8 +8,21 @@ import SuggestionModel
78public 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