@@ -2,10 +2,11 @@ import Foundation
22import OpenAIService
33import Preferences
44import SuggestionModel
5+ import XcodeInspector
56
67public final class OpenAIPromptToCodeService : PromptToCodeServiceType {
78 var service : ( any ChatGPTServiceType ) ?
8-
9+
910 public init ( ) { }
1011
1112 public func stopResponding( ) {
@@ -14,13 +15,9 @@ public final class OpenAIPromptToCodeService: PromptToCodeServiceType {
1415
1516 public func modifyCode(
1617 code: String ,
17- language: CodeLanguage ,
18- indentSize: Int ,
19- usesTabsForIndentation: Bool ,
2018 requirement: String ,
21- projectRootURL: URL ,
22- fileURL: URL ,
23- allCode: String ,
19+ source: PromptToCodeSource ,
20+ isDetached: Bool ,
2421 extraSystemPrompt: String ? ,
2522 generateDescriptionRequirement: Bool ?
2623 ) async throws -> AsyncThrowingStream < ( code: String , description: String ) , Error > {
@@ -31,9 +28,25 @@ public final class OpenAIPromptToCodeService: PromptToCodeServiceType {
3128 {
3229 return " "
3330 }
34- return userPreferredLanguage. isEmpty ? " " : " in \( userPreferredLanguage) "
31+ return userPreferredLanguage. isEmpty ? " " : " in \( userPreferredLanguage) "
3532 } ( )
3633
34+ let editor : EditorInformation = XcodeInspector . shared. focusedEditorContent ?? . init(
35+ editorContent: . init(
36+ content: source. allCode,
37+ lines: [ ] ,
38+ selections: [ source. range] ,
39+ cursorPosition: . outOfScope,
40+ lineAnnotations: [ ]
41+ ) ,
42+ selectedContent: code,
43+ selectedLines: [ ] ,
44+ documentURL: source. documentURL,
45+ projectURL: source. projectRootURL,
46+ relativePath: " " ,
47+ language: source. language
48+ )
49+
3750 let rule : String = {
3851 func generateDescription( index: Int ) -> String {
3952 let generateDescription = generateDescriptionRequirement ?? UserDefaults . shared
@@ -46,7 +59,7 @@ public final class OpenAIPromptToCodeService: PromptToCodeServiceType {
4659 """
4760 : " \( index) . Reply with the result. "
4861 }
49- switch language {
62+ switch editor . language {
5063 case . builtIn( . markdown) , . plaintext:
5164 if code. isEmpty {
5265 return """
@@ -82,20 +95,20 @@ public final class OpenAIPromptToCodeService: PromptToCodeServiceType {
8295 } ( )
8396
8497 let systemPrompt = {
85- switch language {
98+ switch editor . language {
8699 case . builtIn( . markdown) , . plaintext:
87100 if code. isEmpty {
88101 return """
89- You are good at writing in \( language. rawValue) .
90- The active file is: \( fileURL . lastPathComponent) .
102+ You are good at writing in \( editor . language. rawValue) .
103+ The active file is: \( editor . documentURL . lastPathComponent) .
91104 \( extraSystemPrompt ?? " " )
92105
93106 \( rule)
94107 """
95108 } else {
96109 return """
97- You are good at writing in \( language. rawValue) .
98- The active file is: \( fileURL . lastPathComponent) .
110+ You are good at writing in \( editor . language. rawValue) .
111+ The active file is: \( editor . documentURL . lastPathComponent) .
99112 \( extraSystemPrompt ?? " " )
100113
101114 \( rule)
@@ -104,16 +117,16 @@ public final class OpenAIPromptToCodeService: PromptToCodeServiceType {
104117 default :
105118 if code. isEmpty {
106119 return """
107- You are a senior programer in writing in \( language. rawValue) .
108- The active file is: \( fileURL . lastPathComponent) .
120+ You are a senior programer in writing in \( editor . language. rawValue) .
121+ The active file is: \( editor . documentURL . lastPathComponent) .
109122 \( extraSystemPrompt ?? " " )
110123
111124 \( rule)
112125 """
113126 } else {
114127 return """
115- You are a senior programer in writing in \( language. rawValue) .
116- The active file is: \( fileURL . lastPathComponent) .
128+ You are a senior programer in writing in \( editor . language. rawValue) .
129+ The active file is: \( editor . documentURL . lastPathComponent) .
117130 \( extraSystemPrompt ?? " " )
118131
119132 \( rule)
@@ -122,31 +135,44 @@ public final class OpenAIPromptToCodeService: PromptToCodeServiceType {
122135 }
123136 } ( )
124137
138+ let annotations = isDetached
139+ ? [ ]
140+ : extractAnnotations ( editorInformation: editor, source: source)
141+
125142 let firstMessage : String ? = {
126143 if code. isEmpty { return nil }
127- switch language {
144+ switch editor . language {
128145 case . builtIn( . markdown) , . plaintext:
129146 return """
130147 ```
131148 \( code)
132149 ```
150+
151+ line annotations found:
152+ \( annotations. map { " - \( $0) " } . joined ( separator: " \n " ) )
133153 """
134154 default :
135155 return """
136156 ```
137157 \( code)
138158 ```
159+
160+ line annotations found:
161+ \( annotations. map { " - \( $0) " } . joined ( separator: " \n " ) )
139162 """
140163 }
141164 } ( )
142165
166+ let indentation = getCommonLeadingSpaceCount ( code)
167+
143168 let secondMessage = """
144- Requirements:###
145- \( requirement)
146- ###
169+ I will update the code you just provided.
170+ It looks like every line has an indentation of \( indentation) spaces, I will keep that.
171+
172+ What is your requirement?
147173 """
148174
149- let configuration = UserPreferenceChatGPTConfiguration ( )
175+ let configuration = UserPreferenceChatGPTConfiguration ( )
150176 . overriding ( . init( temperature: 0 ) )
151177 let memory = AutoManagedChatGPTMemory (
152178 systemPrompt: systemPrompt,
@@ -161,9 +187,10 @@ public final class OpenAIPromptToCodeService: PromptToCodeServiceType {
161187 if let firstMessage {
162188 await memory. mutateHistory { history in
163189 history. append ( . init( role: . user, content: firstMessage) )
190+ history. append ( . init( role: . assistant, content: secondMessage) )
164191 }
165192 }
166- let stream = try await chatGPTService. send ( content: secondMessage )
193+ let stream = try await chatGPTService. send ( content: requirement )
167194 return . init { continuation in
168195 Task {
169196 var content = " "
@@ -231,5 +258,33 @@ public final class OpenAIPromptToCodeService: PromptToCodeServiceType {
231258
232259 return ( code, description)
233260 }
261+
262+ func getCommonLeadingSpaceCount( _ code: String ) -> Int {
263+ let lines = code. split ( separator: " \n " )
264+ guard !lines. isEmpty else { return 0 }
265+ var commonCount = Int . max
266+ for line in lines {
267+ let count = line. prefix ( while: { $0 == " " } ) . count
268+ commonCount = min ( commonCount, count)
269+ if commonCount == 0 { break }
270+ }
271+ return commonCount
272+ }
273+
274+ func extractAnnotations(
275+ editorInformation: EditorInformation ,
276+ source: PromptToCodeSource
277+ ) -> [ String ] {
278+ guard let annotations = editorInformation. editorContent? . lineAnnotations else { return [ ] }
279+ return annotations
280+ . lazy
281+ . filter { annotation in
282+ annotation. line >= source. range. start. line + 1
283+ && annotation. line <= source. range. end. line + 1
284+ } . map { annotation in
285+ let relativeLine = annotation. line - source. range. start. line
286+ return " line \( relativeLine) : \( annotation. type) \( annotation. message) "
287+ }
288+ }
234289}
235290
0 commit comments