Skip to content

Commit cf3a879

Browse files
committed
Migrate prompt to code to use TCA
1 parent 18203a5 commit cf3a879

16 files changed

+953
-500
lines changed

Core/Sources/Service/GUI/GraphicalUserInterfaceController.swift

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ struct GUI: ReducerProtocol {
2424
set { suggestionWidgetState.chatPanelState.chatTabGroup = newValue }
2525
}
2626

27+
var promptToCodeGroup: PromptToCodeGroup.State {
28+
get { suggestionWidgetState.panelState.content.promptToCodeGroup }
29+
set { suggestionWidgetState.panelState.content.promptToCodeGroup = newValue }
30+
}
31+
2732
#if canImport(ChatTabPersistent)
2833
var persistentState: ChatTabPersistent.State {
2934
get {
@@ -44,6 +49,10 @@ struct GUI: ReducerProtocol {
4449

4550
case suggestionWidget(WidgetFeature.Action)
4651

52+
static func promptToCodeGroup(_ action: PromptToCodeGroup.Action) -> Self {
53+
.suggestionWidget(.panel(.sharedPanel(.promptToCodeGroup(action))))
54+
}
55+
4756
#if canImport(ChatTabPersistent)
4857
case persistent(ChatTabPersistent.Action)
4958
#endif
@@ -267,7 +276,7 @@ public final class GraphicalUserInterfaceController {
267276
}
268277
}
269278
}
270-
279+
271280
func start() {
272281
store.send(.start)
273282
}

Core/Sources/Service/GUI/WidgetDataSource.swift

Lines changed: 1 addition & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -9,81 +9,7 @@ import SuggestionModel
99
import SuggestionWidget
1010

1111
@MainActor
12-
final class WidgetDataSource {
13-
final class PromptToCode {
14-
let promptToCodeService: PromptToCodeService
15-
let provider: PromptToCodeProvider
16-
public init(
17-
promptToCodeService: PromptToCodeService,
18-
provider: PromptToCodeProvider
19-
) {
20-
self.promptToCodeService = promptToCodeService
21-
self.provider = provider
22-
}
23-
}
24-
25-
private(set) var promptToCode: PromptToCode?
26-
27-
init() {}
28-
29-
@discardableResult
30-
func createPromptToCode(
31-
for url: URL,
32-
projectURL: URL,
33-
selectedCode: String,
34-
allCode: String,
35-
selectionRange: CursorRange,
36-
language: CodeLanguage,
37-
identSize: Int = 4,
38-
usesTabsForIndentation: Bool = false,
39-
extraSystemPrompt: String?,
40-
generateDescriptionRequirement: Bool?,
41-
name: String?
42-
) async -> PromptToCodeService {
43-
let build = {
44-
let service = PromptToCodeService(
45-
code: selectedCode,
46-
selectionRange: selectionRange,
47-
language: language,
48-
identSize: identSize,
49-
usesTabsForIndentation: usesTabsForIndentation,
50-
projectRootURL: projectURL,
51-
fileURL: url,
52-
allCode: allCode,
53-
extraSystemPrompt: extraSystemPrompt,
54-
generateDescriptionRequirement: generateDescriptionRequirement
55-
)
56-
let provider = PromptToCodeProvider(
57-
service: service,
58-
name: name,
59-
onClosePromptToCode: { [weak self] in
60-
self?.removePromptToCode()
61-
let presenter = PresentInWindowSuggestionPresenter()
62-
presenter.closePromptToCode(fileURL: url)
63-
if let app = ActiveApplicationMonitor.shared.previousApp, app.isXcode {
64-
Task { @MainActor in
65-
try await Task.sleep(nanoseconds: 200_000_000)
66-
app.activate()
67-
}
68-
}
69-
}
70-
)
71-
return PromptToCode(promptToCodeService: service, provider: provider)
72-
}
73-
74-
let newPromptToCode = build()
75-
promptToCode = newPromptToCode
76-
return newPromptToCode.promptToCodeService
77-
}
78-
79-
func removePromptToCode() {
80-
promptToCode = nil
81-
}
82-
83-
func cleanup(for url: URL) {
84-
// removePromptToCode(for: url)
85-
}
86-
}
12+
final class WidgetDataSource {}
8713

8814
extension WidgetDataSource: SuggestionWidgetDataSource {
8915
func suggestionForFile(at url: URL) async -> SuggestionProvider? {
@@ -138,9 +64,5 @@ extension WidgetDataSource: SuggestionWidgetDataSource {
13864
}
13965
return nil
14066
}
141-
142-
func promptToCodeForFile(at url: URL) async -> PromptToCodeProvider? {
143-
return promptToCode?.provider
144-
}
14567
}
14668

Core/Sources/Service/ScheduledCleaner.swift

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ public final class ScheduledCleaner {
1717
self.workspacePool = workspacePool
1818
self.guiController = guiController
1919
}
20-
20+
2121
func start() {
2222
// occasionally cleanup workspaces.
2323
Task { @ServiceActor in
@@ -58,9 +58,13 @@ public final class ScheduledCleaner {
5858
for (url, workspace) in workspacePool.workspaces {
5959
if workspace.isExpired, workspaceInfos[.url(url)] == nil {
6060
Logger.service.info("Remove idle workspace")
61-
for url in workspace.filespaces.keys {
62-
await guiController.widgetDataSource.cleanup(for: url)
63-
}
61+
_ = await Task { @MainActor in
62+
guiController.viewStore.send(
63+
.promptToCodeGroup(.discardExpiredPromptToCode(documentURLs: Array(
64+
workspace.filespaces.keys
65+
)))
66+
)
67+
}.result
6468
await workspace.cleanUp(availableTabs: [])
6569
workspacePool.removeWorkspace(url: url)
6670
} else {
@@ -74,7 +78,11 @@ public final class ScheduledCleaner {
7478
availableTabs: tabs
7579
) {
7680
Logger.service.info("Remove idle filespace")
77-
await guiController.widgetDataSource.cleanup(for: url)
81+
_ = await Task { @MainActor in
82+
guiController.viewStore.send(
83+
.promptToCodeGroup(.discardExpiredPromptToCode(documentURLs: [url]))
84+
)
85+
}.result
7886
}
7987
}
8088
// cleanup workspace

Core/Sources/Service/SuggestionCommandHandler/WindowBaseCommandHandler.swift

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -190,20 +190,24 @@ struct WindowBaseCommandHandler: SuggestionCommandHandler {
190190
var cursorPosition = editor.cursorPosition
191191
var extraInfo = SuggestionInjector.ExtraInfo()
192192

193-
let dataSource = Service.shared.guiController.widgetDataSource
193+
let viewStore = Service.shared.guiController.viewStore
194194

195-
if let service = await dataSource.promptToCode?.promptToCodeService {
196-
let rangeStart = service.selectionRange?.start ?? editor.cursorPosition
195+
if let promptToCode = viewStore.state.promptToCodeGroup.activePromptToCode {
196+
if promptToCode.isAttachedToSelectionRange, promptToCode.documentURL != fileURL {
197+
return nil
198+
}
199+
200+
let rangeStart = promptToCode.selectionRange?.start ?? editor.cursorPosition
197201

198202
let suggestion = CodeSuggestion(
199-
text: service.code,
203+
text: promptToCode.code,
200204
position: rangeStart,
201205
uuid: UUID().uuidString,
202-
range: service.selectionRange ?? .init(
206+
range: promptToCode.selectionRange ?? .init(
203207
start: editor.cursorPosition,
204208
end: editor.cursorPosition
205209
),
206-
displayText: service.code
210+
displayText: promptToCode.code
207211
)
208212

209213
injector.acceptSuggestion(
@@ -213,16 +217,19 @@ struct WindowBaseCommandHandler: SuggestionCommandHandler {
213217
extraInfo: &extraInfo
214218
)
215219

216-
if service.isContinuous {
217-
service.selectionRange = .init(
218-
start: rangeStart,
219-
end: cursorPosition
220+
_ = await Task { @MainActor [cursorPosition] in
221+
viewStore.send(
222+
.promptToCodeGroup(.updatePromptToCodeRange(
223+
id: promptToCode.id,
224+
range: .init(start: rangeStart, end: cursorPosition)
225+
))
220226
)
221-
presenter.presentPromptToCode(fileURL: fileURL)
222-
} else {
223-
await dataSource.removePromptToCode()
224-
presenter.closePromptToCode(fileURL: fileURL)
225-
}
227+
viewStore.send(
228+
.promptToCodeGroup(.discardAcceptedPromptToCodeIfNotContinuous(
229+
id: promptToCode.id
230+
))
231+
)
232+
}.result
226233

227234
return .init(
228235
content: String(lines.joined(separator: "")),
@@ -348,7 +355,7 @@ extension WindowBaseCommandHandler {
348355
presenter.markAsProcessing(true)
349356
defer { presenter.markAsProcessing(false) }
350357
let fileURL = try await Environment.fetchCurrentFileURL()
351-
let (workspace, _) = try await Service.shared.workspacePool
358+
let (workspace, filespace) = try await Service.shared.workspacePool
352359
.fetchOrCreateWorkspaceAndFilespace(fileURL: fileURL)
353360
guard workspace.suggestionPlugin?.isSuggestionFeatureEnabled ?? false else {
354361
presenter.presentErrorMessage("Prompt to code is disabled for this project")
@@ -391,26 +398,25 @@ extension WindowBaseCommandHandler {
391398
)
392399
}() as (String, CursorRange)
393400

394-
let dataSource = Service.shared.guiController.widgetDataSource
395-
396-
let promptToCode = await dataSource.createPromptToCode(
397-
for: fileURL,
398-
projectURL: workspace.projectRootURL,
399-
selectedCode: code,
400-
allCode: editor.content,
401-
selectionRange: selection,
402-
language: codeLanguage,
403-
extraSystemPrompt: extraSystemPrompt,
404-
generateDescriptionRequirement: generateDescription,
405-
name: name
406-
)
407-
408-
promptToCode.isContinuous = isContinuous
409-
if let prompt, !prompt.isEmpty {
410-
Task { try await promptToCode.modifyCode(prompt: prompt) }
411-
}
412-
413-
presenter.presentPromptToCode(fileURL: fileURL)
401+
let viewStore = Service.shared.guiController.viewStore
402+
403+
_ = await Task { @MainActor in
404+
viewStore.send(.promptToCodeGroup(.createPromptToCode(.init(
405+
code: code,
406+
selectionRange: selection,
407+
language: codeLanguage,
408+
identSize: filespace.codeMetadata.indentSize ?? 4,
409+
usesTabsForIndentation: filespace.codeMetadata.usesTabsForIndentation ?? false,
410+
documentURL: fileURL,
411+
projectRootURL: workspace.projectRootURL,
412+
allCode: editor.content,
413+
isContinuous: isContinuous,
414+
commandName: name,
415+
defaultPrompt: prompt ?? "",
416+
extraSystemPrompt: extraSystemPrompt,
417+
generateDescriptionRequirement: generateDescription
418+
))))
419+
}.result
414420
}
415421

416422
func executeSingleRoundDialog(

Core/Sources/Service/SuggestionPresenter/PresentInWindowSuggestionPresenter.swift

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -55,19 +55,5 @@ struct PresentInWindowSuggestionPresenter {
5555
controller.presentChatRoom()
5656
}
5757
}
58-
59-
func presentPromptToCode(fileURL: URL) {
60-
Task { @MainActor in
61-
let controller = Service.shared.guiController.widgetController
62-
controller.presentPromptToCode()
63-
}
64-
}
65-
66-
func closePromptToCode(fileURL: URL) {
67-
Task { @MainActor in
68-
let controller = Service.shared.guiController.widgetController
69-
controller.discardPromptToCode()
70-
}
71-
}
7258
}
7359

0 commit comments

Comments
 (0)