@@ -4,7 +4,7 @@ import XcodeInspector
4
4
import AXHelper
5
5
import ApplicationServices
6
6
import AppActivator
7
-
7
+ import LanguageServerProtocol
8
8
9
9
public struct ChatInjector {
10
10
public init ( ) { }
@@ -22,76 +22,126 @@ public struct ChatInjector {
22
22
var lines = editorContent. content. splitByNewLine (
23
23
omittingEmptySubsequences: false
24
24
) . map { String ( $0) }
25
- // Ensure the line number is within the bounds of the file
25
+
26
26
guard cursorPosition. line <= lines. count else { return }
27
27
28
28
var modifications : [ Modification ] = [ ]
29
29
30
- // remove selection
31
- // make sure there is selection exist and valid
30
+ // Handle selection deletion
32
31
if let selection = editorContent. selections. first,
33
- selection. isValid,
34
- selection. start. line < lines. endIndex {
32
+ selection. isValid,
33
+ selection. start. line < lines. endIndex {
35
34
let selectionEndLine = min ( selection. end. line, lines. count - 1 )
36
35
let deletedSelection = CursorRange (
37
36
start: selection. start,
38
37
end: . init( line: selectionEndLine, character: selection. end. character)
39
38
)
40
39
modifications. append ( . deletedSelection( deletedSelection) )
41
40
lines = lines. applying ( [ . deletedSelection( deletedSelection) ] )
42
-
43
- // update cursorPosition to the start of selection
44
41
cursorPosition = selection. start
45
42
}
46
43
47
- let targetLine = lines [ cursorPosition. line]
44
+ let insertionRange = CursorRange (
45
+ start: cursorPosition,
46
+ end: cursorPosition
47
+ )
48
48
49
- // Determine the indention level of the target line
50
- let leadingWhitespace = cursorPosition. character > 0 ? targetLine. prefix { $0. isWhitespace } : " "
51
- let indentation = String ( leadingWhitespace)
49
+ try Self . performInsertion (
50
+ content: codeBlock,
51
+ range: insertionRange,
52
+ lines: & lines,
53
+ modifications: & modifications,
54
+ focusElement: focusElement
55
+ )
52
56
53
- // Insert codeblock at the specified position
54
- let index = targetLine. index ( targetLine. startIndex, offsetBy: min ( cursorPosition. character, targetLine. count) )
55
- let before = targetLine [ ..< index]
56
- let after = targetLine [ index... ]
57
+ } catch {
58
+ print ( " Failed to insert code block: \( error) " )
59
+ }
60
+ }
61
+
62
+ public static func insertSuggestion( suggestion: String , range: CursorRange , lines: [ String ] ) {
63
+ do {
64
+ guard let focusElement = XcodeInspector . shared. focusedElement,
65
+ focusElement. description == " Source Editor "
66
+ else { return }
57
67
58
- let codeBlockLines = codeBlock. splitByNewLine (
59
- omittingEmptySubsequences: false
60
- ) . enumerated ( ) . map { ( index, element) -> String in
61
- return index == 0 ? String ( element) : indentation + String( element)
62
- }
63
-
64
- var toBeInsertedLines = [ String] ( )
65
- toBeInsertedLines. append ( String ( before) + codeBlockLines. first!)
66
- toBeInsertedLines. append ( contentsOf: codeBlockLines. dropFirst ( ) . dropLast ( ) )
67
- toBeInsertedLines. append ( codeBlockLines. last! + String( after) )
68
+ guard range. start. line >= 0 ,
69
+ range. start. line < lines. count,
70
+ range. end. line >= 0 ,
71
+ range. end. line < lines. count
72
+ else { return }
68
73
69
- lines. replaceSubrange ( ( cursorPosition. line) ... ( cursorPosition. line) , with: toBeInsertedLines)
74
+ var lines = lines
75
+ var modifications : [ Modification ] = [ ]
70
76
71
- // Join the lines
72
- let newContent = String ( lines. joined ( separator: " \n " ) )
77
+ if range. isValid {
78
+ modifications. append ( . deletedSelection( range) )
79
+ lines = lines. applying ( [ . deletedSelection( range) ] )
80
+ }
73
81
74
- // Inject updated content
75
- let newCursorPosition = CursorPosition (
76
- line: cursorPosition. line + codeBlockLines. count - 1 ,
77
- character: codeBlockLines. last? . count ?? 0
78
- )
79
- modifications. append ( . inserted( cursorPosition. line, toBeInsertedLines) )
80
- try AXHelper ( ) . injectUpdatedCodeWithAccessibilityAPI (
81
- . init(
82
- content: newContent,
83
- newSelection: . cursor( newCursorPosition) ,
84
- modifications: modifications
85
- ) ,
86
- focusElement: focusElement,
87
- onSuccess: {
88
- NSWorkspace . activatePreviousActiveXcode ( )
89
- }
90
-
82
+ try performInsertion (
83
+ content: suggestion,
84
+ range: range,
85
+ lines: & lines,
86
+ modifications: & modifications,
87
+ focusElement: focusElement
91
88
)
92
89
93
90
} catch {
94
- print ( " Failed to insert code block: \( error) " )
91
+ print ( " Failed to insert suggestion: \( error) " )
92
+ }
93
+ }
94
+
95
+ private static func performInsertion(
96
+ content: String ,
97
+ range: CursorRange ,
98
+ lines: inout [ String ] ,
99
+ modifications: inout [ Modification ] ,
100
+ focusElement: AXUIElement
101
+ ) throws {
102
+ let targetLine = lines [ range. start. line]
103
+ let leadingWhitespace = range. start. character > 0 ? targetLine. prefix { $0. isWhitespace } : " "
104
+ let indentation = String ( leadingWhitespace)
105
+
106
+ let index = targetLine. index ( targetLine. startIndex, offsetBy: min ( range. start. character, targetLine. count) )
107
+ let before = targetLine [ ..< index]
108
+ let after = targetLine [ index... ]
109
+
110
+ let contentLines = content. splitByNewLine (
111
+ omittingEmptySubsequences: false
112
+ ) . enumerated ( ) . map { ( index, element) -> String in
113
+ return index == 0 ? String ( element) : indentation + String( element)
114
+ }
115
+
116
+ var toBeInsertedLines = [ String] ( )
117
+ if contentLines. count > 1 {
118
+ toBeInsertedLines. append ( String ( before) + contentLines. first!)
119
+ toBeInsertedLines. append ( contentsOf: contentLines. dropFirst ( ) . dropLast ( ) )
120
+ toBeInsertedLines. append ( contentLines. last! + String( after) )
121
+ } else {
122
+ toBeInsertedLines. append ( String ( before) + contentLines. first! + String( after) )
95
123
}
124
+
125
+ lines. replaceSubrange ( ( range. start. line) ... ( range. start. line) , with: toBeInsertedLines)
126
+
127
+ let newContent = String ( lines. joined ( separator: " \n " ) )
128
+ let newCursorPosition = CursorPosition (
129
+ line: range. start. line + contentLines. count - 1 ,
130
+ character: contentLines. last? . count ?? 0
131
+ )
132
+
133
+ modifications. append ( . inserted( range. start. line, toBeInsertedLines) )
134
+
135
+ try AXHelper ( ) . injectUpdatedCodeWithAccessibilityAPI (
136
+ . init(
137
+ content: newContent,
138
+ newSelection: . cursor( newCursorPosition) ,
139
+ modifications: modifications
140
+ ) ,
141
+ focusElement: focusElement,
142
+ onSuccess: {
143
+ NSWorkspace . activatePreviousActiveXcode ( )
144
+ }
145
+ )
96
146
}
97
147
}
0 commit comments