Skip to content

Commit 41290ee

Browse files
committed
Fix PromptToCodeCustomization
1 parent e7bde03 commit 41290ee

File tree

13 files changed

+208
-103
lines changed

13 files changed

+208
-103
lines changed

Core/Sources/Service/GUI/GraphicalUserInterfaceController.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,13 @@ public final class GraphicalUserInterfaceController {
337337
self?.store.send(.openChatPanel(forceDetach: false, activateThisApp: true))
338338
}
339339
}
340+
suggestionDependency.onOpenModificationButtonClicked = {
341+
Task {
342+
guard let content = await PseudoCommandHandler().getEditorContent(sourceEditor: nil)
343+
else { return }
344+
_ = try await WindowBaseCommandHandler().promptToCode(editor: content)
345+
}
346+
}
340347
suggestionDependency.onCustomCommandClicked = { command in
341348
Task {
342349
let commandHandler = PseudoCommandHandler()

Core/Sources/Service/SuggestionCommandHandler/PseudoCommandHandler.swift

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -273,21 +273,13 @@ struct PseudoCommandHandler: CommandHandler {
273273
}
274274

275275
func presentModification(state: Shared<ModificationState>) async {
276-
do {
277-
@Dependency(\.workspacePool) var workspacePool
278-
let (_, filespace) = try await workspacePool
279-
.fetchOrCreateWorkspaceAndFilespace(fileURL: state.wrappedValue.source.documentURL)
280-
let store = await Service.shared.guiController.store
281-
await store.send(.promptToCodeGroup(.createPromptToCode(.init(
282-
promptToCodeState: state,
283-
indentSize: filespace.codeMetadata.indentSize ?? 4,
284-
usesTabsForIndentation: filespace.codeMetadata.usesTabsForIndentation ?? false,
285-
commandName: nil,
286-
isContinuous: false
287-
), sendImmediately: false)))
288-
} catch {
289-
toast.toast(content: error.localizedDescription, type: .error)
290-
}
276+
let store = await Service.shared.guiController.store
277+
await store.send(.promptToCodeGroup(.createPromptToCode(.init(
278+
promptToCodeState: state,
279+
instruction: nil,
280+
commandName: nil,
281+
isContinuous: false
282+
), sendImmediately: false)))
291283
}
292284

293285
func acceptSuggestion() async {

Core/Sources/Service/SuggestionCommandHandler/WindowBaseCommandHandler.swift

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -472,12 +472,10 @@ extension WindowBaseCommandHandler {
472472
lines: editor.lines
473473
),
474474
snippets: IdentifiedArray(uniqueElements: snippets),
475-
instruction: newPrompt ?? "",
476475
extraSystemPrompt: newExtraSystemPrompt ?? "",
477476
isAttachedToTarget: true
478477
)),
479-
indentSize: filespace.codeMetadata.indentSize ?? 4,
480-
usesTabsForIndentation: filespace.codeMetadata.usesTabsForIndentation ?? false,
478+
instruction: newPrompt,
481479
commandName: name,
482480
isContinuous: isContinuous
483481
))))

Core/Sources/SuggestionWidget/FeatureReducers/CircularWidget.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ public struct CircularWidget {
2424
case widgetClicked
2525
case detachChatPanelToggleClicked
2626
case openChatButtonClicked
27+
case openModificationButtonClicked
2728
case runCustomCommandButtonClicked(CustomCommand)
2829
case markIsProcessing
2930
case endIsProcessing
@@ -45,6 +46,11 @@ public struct CircularWidget {
4546
suggestionWidgetControllerDependency.onOpenChatClicked()
4647
}
4748

49+
case .openModificationButtonClicked:
50+
return .run { _ in
51+
suggestionWidgetControllerDependency.onOpenModificationButtonClicked()
52+
}
53+
4854
case let .runCustomCommandButtonClicked(command):
4955
return .run { _ in
5056
suggestionWidgetControllerDependency.onCustomCommandClicked(command)

Core/Sources/SuggestionWidget/FeatureReducers/PromptToCodeGroup.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ public struct PromptToCodeGroup {
6363
// insert at 0 so it has high priority then the other detached prompt to codes
6464
state.promptToCodes.insert(newPromptToCode, at: 0)
6565
return .run { send in
66-
if sendImmediately, !newPromptToCode.promptToCodeState.instruction.isEmpty {
66+
if sendImmediately,
67+
!newPromptToCode.contextInputController.instruction.string.isEmpty
68+
{
6769
await send(.promptToCode(newPromptToCode.id, .modifyCodeButtonTapped))
6870
}
6971
}.cancellable(

Core/Sources/SuggestionWidget/FeatureReducers/PromptToCodePanel.swift

Lines changed: 52 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import ComposableArchitecture
33
import CustomAsyncAlgorithms
44
import Dependencies
55
import Foundation
6-
import Preferences
76
import ModificationBasic
7+
import Preferences
88
import PromptToCodeCustomization
99
import PromptToCodeService
1010
import 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+

Core/Sources/SuggestionWidget/ModuleDependency.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import XcodeInspector
1212
public final class SuggestionWidgetControllerDependency {
1313
public var suggestionWidgetDataSource: SuggestionWidgetDataSource?
1414
public var onOpenChatClicked: () -> Void = {}
15+
public var onOpenModificationButtonClicked: () -> Void = {}
1516
public var onCustomCommandClicked: (CustomCommand) -> Void = { _ in }
1617
var windowsController: WidgetWindowsController?
1718

0 commit comments

Comments
 (0)