@@ -3,8 +3,8 @@ import ComposableArchitecture
33import CustomAsyncAlgorithms
44import Dependencies
55import Foundation
6- import Preferences
76import ModificationBasic
7+ import Preferences
88import PromptToCodeCustomization
99import PromptToCodeService
1010import SuggestionBasic
@@ -18,11 +18,11 @@ public struct PromptToCodePanel {
1818 }
1919
2020 @Shared public var promptToCodeState : ModificationState
21+ @ObservationStateIgnored
22+ public var contextInputController : PromptToCodeContextInputController
2123
2224 public var id : URL { promptToCodeState. source. documentURL }
2325
24- public var indentSize : Int
25- public var usesTabsForIndentation : Bool
2626 public var commandName : String ?
2727 public var isContinuous : Bool
2828 public var focusedField : FocusField ? = . textField
@@ -34,7 +34,7 @@ public struct PromptToCodePanel {
3434 public var canRevert : Bool { !promptToCodeState. history. isEmpty }
3535
3636 public var generateDescriptionRequirement : Bool
37-
37+
3838 public var hasEnded = false
3939
4040 public var snippetPanels : IdentifiedArrayOf < PromptToCodeSnippetPanel . State > {
@@ -54,20 +54,20 @@ public struct PromptToCodePanel {
5454
5555 public init (
5656 promptToCodeState: Shared < ModificationState > ,
57- indentSize: Int ,
58- usesTabsForIndentation: Bool ,
57+ instruction: String ? ,
5958 commandName: String ? = nil ,
6059 isContinuous: Bool = false ,
6160 generateDescriptionRequirement: Bool = UserDefaults . shared
6261 . value ( for: \. promptToCodeGenerateDescription)
6362 ) {
6463 _promptToCodeState = promptToCodeState
6564 self . isContinuous = isContinuous
66- self . indentSize = indentSize
67- self . usesTabsForIndentation = usesTabsForIndentation
6865 self . generateDescriptionRequirement = generateDescriptionRequirement
6966 self . commandName = commandName
67+ contextInputController = PromptToCodeCustomization
68+ . contextInputControllerFactory ( promptToCodeState)
7069 focusedField = . textField
70+ contextInputController. instruction = instruction. map ( NSAttributedString . init ( string: ) ) ?? . init( )
7171 }
7272 }
7373
@@ -83,12 +83,10 @@ public struct PromptToCodePanel {
8383 case cancelButtonTapped
8484 case acceptButtonTapped
8585 case acceptAndContinueButtonTapped
86- case appendNewLineToPromptButtonTapped
8786 case snippetPanel( IdentifiedActionOf < PromptToCodeSnippetPanel > )
8887 }
8988
9089 @Dependency ( \. commandHandler) var commandHandler
91- @Dependency ( \. promptToCodeService) var promptToCodeService
9290 @Dependency ( \. activateThisApp) var activateThisApp
9391 @Dependency ( \. activatePreviousActiveXcode) var activatePreviousActiveXcode
9492
@@ -118,46 +116,54 @@ public struct PromptToCodePanel {
118116 case . modifyCodeButtonTapped:
119117 guard !state. promptToCodeState. isGenerating else { return . none }
120118 let copiedState = state
119+ let contextInputController = state. contextInputController
121120 state. promptToCodeState. isGenerating = true
122- state. promptToCodeState. pushHistory ( )
121+ state. promptToCodeState. pushHistory ( instruction : . init ( attributedString : contextInputController . instruction ) )
123122 let snippets = state. promptToCodeState. snippets
124123
125124 return . run { send in
126125 do {
126+ let context = await contextInputController. resolveContext ( )
127+ let agentFactory = context. agent ?? { SimpleModificationAgent ( ) }
127128 _ = try await withThrowingTaskGroup ( of: Void . self) { group in
128129 for snippet in snippets {
129130 group. addTask {
130- let stream = try await promptToCodeService. modifyCode (
131+ let agent = agentFactory ( )
132+ let stream = agent. send ( . init(
131133 code: snippet. originalCode,
132- requirement: copiedState . promptToCodeState . instruction,
134+ requirement: context . instruction,
133135 source: . init(
134136 language: copiedState. promptToCodeState. source. language,
135137 documentURL: copiedState. promptToCodeState. source
136138 . documentURL,
137139 projectRootURL: copiedState. promptToCodeState. source
138140 . projectRootURL,
139141 content: copiedState. promptToCodeState. source. content,
140- lines: copiedState. promptToCodeState. source. lines,
141- range: snippet. attachedRange
142+ lines: copiedState. promptToCodeState. source. lines
142143 ) ,
143144 isDetached: !copiedState. promptToCodeState
144145 . isAttachedToTarget,
145146 extraSystemPrompt: copiedState. promptToCodeState
146147 . extraSystemPrompt,
147- generateDescriptionRequirement: copiedState
148- . generateDescriptionRequirement
149- ) . timedDebounce ( for: 0.2 )
148+ range: snippet. attachedRange,
149+ references: context. references,
150+ topics: context. topics
151+ ) ) . timedDebounce ( for: 0.5 )
150152
151153 do {
152- for try await fragment in stream {
154+ for try await response in stream {
153155 try Task . checkCancellation ( )
154- await send ( . snippetPanel( . element(
155- id: snippet. id,
156- action: . modifyCodeChunkReceived(
157- code: fragment. code,
158- description: fragment. description
159- )
160- ) ) )
156+
157+ switch response {
158+ case let . code( code) :
159+ await send ( . snippetPanel( . element(
160+ id: snippet. id,
161+ action: . modifyCodeChunkReceived(
162+ code: code,
163+ description: " "
164+ )
165+ ) ) )
166+ }
161167 }
162168 } catch is CancellationError {
163169 throw CancellationError ( )
@@ -173,8 +179,7 @@ public struct PromptToCodePanel {
173179 await send ( . snippetPanel( . element(
174180 id: snippet. id,
175181 action: . modifyCodeFailed(
176- error: error
177- . localizedDescription
182+ error: error. localizedDescription
178183 )
179184 ) ) )
180185 }
@@ -194,16 +199,17 @@ public struct PromptToCodePanel {
194199 } . cancellable ( id: CancellationKey . modifyCode ( state. id) , cancelInFlight: true )
195200
196201 case . revertButtonTapped:
197- state. promptToCodeState. popHistory ( )
202+ if let instruction = state. promptToCodeState. popHistory ( ) {
203+ state. contextInputController. instruction = instruction
204+ }
198205 return . none
199206
200207 case . stopRespondingButtonTapped:
201208 state. promptToCodeState. isGenerating = false
202- promptToCodeService. stopResponding ( )
203209 return . cancel( id: CancellationKey . modifyCode ( state. id) )
204210
205211 case . modifyCodeFinished:
206- state. promptToCodeState . instruction = " "
212+ state. contextInputController . instruction = . init ( " " )
207213 state. promptToCodeState. isGenerating = false
208214
209215 if state. promptToCodeState. snippets. allSatisfy ( { snippet in
@@ -221,7 +227,6 @@ public struct PromptToCodePanel {
221227 return . none
222228
223229 case . cancelButtonTapped:
224- promptToCodeService. stopResponding ( )
225230 return . cancel( id: CancellationKey . modifyCode ( state. id) )
226231
227232 case . acceptButtonTapped:
@@ -230,16 +235,12 @@ public struct PromptToCodePanel {
230235 await commandHandler. acceptModification ( )
231236 activatePreviousActiveXcode ( )
232237 }
233-
238+
234239 case . acceptAndContinueButtonTapped:
235240 return . run { _ in
236241 await commandHandler. acceptModification ( )
237242 activateThisApp ( )
238243 }
239-
240- case . appendNewLineToPromptButtonTapped:
241- state. promptToCodeState. instruction += " \n "
242- return . none
243244 }
244245 }
245246
@@ -288,3 +289,17 @@ public struct PromptToCodeSnippetPanel {
288289 }
289290}
290291
292+ final class DefaultPromptToCodeContextInputControllerDelegate : PromptToCodeContextInputControllerDelegate {
293+ let store : StoreOf < PromptToCodePanel >
294+
295+ init ( store: StoreOf < PromptToCodePanel > ) {
296+ self . store = store
297+ }
298+
299+ func modifyCodeButtonClicked( ) {
300+ Task {
301+ await store. send ( . modifyCodeButtonTapped)
302+ }
303+ }
304+ }
305+
0 commit comments