@@ -161,6 +161,45 @@ struct PseudoCommandHandler {
161161 }
162162 }
163163
164+ func acceptPromptToCode( ) async {
165+ do {
166+ if UserDefaults . shared. value ( for: \. alwaysAcceptSuggestionWithAccessibilityAPI) {
167+ throw CancellationError ( )
168+ }
169+ try await Environment . triggerAction ( " Accept Prompt to Code " )
170+ } catch {
171+ guard let xcode = ActiveApplicationMonitor . shared. activeXcode
172+ ?? ActiveApplicationMonitor . shared. latestXcode else { return }
173+ let application = AXUIElementCreateApplication ( xcode. processIdentifier)
174+ guard let focusElement = application. focusedElement,
175+ focusElement. description == " Source Editor "
176+ else { return }
177+ guard let ( content, lines, _, cursorPosition) = await getFileContent ( sourceEditor: nil )
178+ else {
179+ PresentInWindowSuggestionPresenter ( )
180+ . presentErrorMessage ( " Unable to get file content. " )
181+ return
182+ }
183+ let handler = WindowBaseCommandHandler ( )
184+ do {
185+ guard let result = try await handler. acceptPromptToCode ( editor: . init(
186+ content: content,
187+ lines: lines,
188+ uti: " " ,
189+ cursorPosition: cursorPosition,
190+ selections: [ ] ,
191+ tabSize: 0 ,
192+ indentSize: 0 ,
193+ usesTabsForIndentation: false
194+ ) ) else { return }
195+
196+ try injectUpdatedCodeWithAccessibilityAPI ( result, focusElement: focusElement)
197+ } catch {
198+ PresentInWindowSuggestionPresenter ( ) . presentError ( error)
199+ }
200+ }
201+ }
202+
164203 func acceptSuggestion( ) async {
165204 do {
166205 if UserDefaults . shared. value ( for: \. alwaysAcceptSuggestionWithAccessibilityAPI) {
@@ -174,12 +213,7 @@ struct PseudoCommandHandler {
174213 guard let focusElement = application. focusedElement,
175214 focusElement. description == " Source Editor "
176215 else { return }
177- guard let (
178- content,
179- lines,
180- _,
181- cursorPosition
182- ) = await getFileContent ( sourceEditor: nil )
216+ guard let ( content, lines, _, cursorPosition) = await getFileContent ( sourceEditor: nil )
183217 else {
184218 PresentInWindowSuggestionPresenter ( )
185219 . presentErrorMessage ( " Unable to get file content. " )
@@ -198,52 +232,7 @@ struct PseudoCommandHandler {
198232 usesTabsForIndentation: false
199233 ) ) else { return }
200234
201- let oldPosition = focusElement. selectedTextRange
202- let oldScrollPosition = focusElement. parent? . verticalScrollBar? . doubleValue
203-
204- let error = AXUIElementSetAttributeValue (
205- focusElement,
206- kAXValueAttribute as CFString ,
207- result. content as CFTypeRef
208- )
209-
210- if error != AXError . success {
211- PresentInWindowSuggestionPresenter ( )
212- . presentErrorMessage ( " Fail to set editor content. " )
213- }
214-
215- if let selection = result. newSelection {
216- var range = convertCursorRangeToRange ( selection, in: result. content)
217- if let value = AXValueCreate ( . cfRange, & range) {
218- AXUIElementSetAttributeValue (
219- focusElement,
220- kAXSelectedTextRangeAttribute as CFString ,
221- value
222- )
223- }
224- } else if let oldPosition {
225- var range = CFRange (
226- location: oldPosition. lowerBound,
227- length: 0
228- )
229- if let value = AXValueCreate ( . cfRange, & range) {
230- AXUIElementSetAttributeValue (
231- focusElement,
232- kAXSelectedTextRangeAttribute as CFString ,
233- value
234- )
235- }
236- }
237-
238- if let oldScrollPosition,
239- let scrollBar = focusElement. parent? . verticalScrollBar
240- {
241- AXUIElementSetAttributeValue (
242- scrollBar,
243- kAXValueAttribute as CFString ,
244- oldScrollPosition as CFTypeRef
245- )
246- }
235+ try injectUpdatedCodeWithAccessibilityAPI ( result, focusElement: focusElement)
247236 } catch {
248237 PresentInWindowSuggestionPresenter ( ) . presentError ( error)
249238 }
@@ -252,6 +241,64 @@ struct PseudoCommandHandler {
252241}
253242
254243extension PseudoCommandHandler {
244+ /// When Xcode commands are not available, we can fallback to directly
245+ /// set the value of the editor with Accessibility API.
246+ func injectUpdatedCodeWithAccessibilityAPI(
247+ _ result: UpdatedContent ,
248+ focusElement: AXUIElement
249+ ) throws {
250+ let oldPosition = focusElement. selectedTextRange
251+ let oldScrollPosition = focusElement. parent? . verticalScrollBar? . doubleValue
252+
253+ let error = AXUIElementSetAttributeValue (
254+ focusElement,
255+ kAXValueAttribute as CFString ,
256+ result. content as CFTypeRef
257+ )
258+
259+ if error != AXError . success {
260+ PresentInWindowSuggestionPresenter ( )
261+ . presentErrorMessage ( " Fail to set editor content. " )
262+ }
263+
264+ // recover selection range
265+
266+ if let selection = result. newSelection {
267+ var range = convertCursorRangeToRange ( selection, in: result. content)
268+ if let value = AXValueCreate ( . cfRange, & range) {
269+ AXUIElementSetAttributeValue (
270+ focusElement,
271+ kAXSelectedTextRangeAttribute as CFString ,
272+ value
273+ )
274+ }
275+ } else if let oldPosition {
276+ var range = CFRange (
277+ location: oldPosition. lowerBound,
278+ length: 0
279+ )
280+ if let value = AXValueCreate ( . cfRange, & range) {
281+ AXUIElementSetAttributeValue (
282+ focusElement,
283+ kAXSelectedTextRangeAttribute as CFString ,
284+ value
285+ )
286+ }
287+ }
288+
289+ // recover scroll position
290+
291+ if let oldScrollPosition,
292+ let scrollBar = focusElement. parent? . verticalScrollBar
293+ {
294+ AXUIElementSetAttributeValue (
295+ scrollBar,
296+ kAXValueAttribute as CFString ,
297+ oldScrollPosition as CFTypeRef
298+ )
299+ }
300+ }
301+
255302 func getFileContent( sourceEditor: AXUIElement ? ) async
256303 -> (
257304 content: String ,
0 commit comments