Skip to content

Commit b539596

Browse files
committed
Support restoring chat tabs
1 parent ff94f17 commit b539596

File tree

3 files changed

+114
-82
lines changed

3 files changed

+114
-82
lines changed

Core/Sources/Service/GUI/ChatTabFactory.swift

Lines changed: 72 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -25,73 +25,82 @@ enum ChatTabFactory {
2525

2626
let collection = [
2727
folderIfNeeded(ChatGPTChatTab.chatBuilders(), title: ChatGPTChatTab.name),
28-
folderIfNeeded(BrowserChatTab.chatBuilders(externalDependency: .init(
29-
getEditorContent: {
30-
guard let editor = XcodeInspector.shared.focusedEditor else {
31-
return .init(selectedText: "", language: "", fileContent: "")
32-
}
33-
let content = editor.content
34-
return .init(
35-
selectedText: content.selectedContent,
36-
language: languageIdentifierFromFileURL(
37-
XcodeInspector.shared
38-
.activeDocumentURL
39-
)
40-
.rawValue,
41-
fileContent: content.content
42-
)
43-
},
44-
handleCustomCommand: { command, prompt in
45-
switch command.feature {
46-
case let .chatWithSelection(extraSystemPrompt, _, useExtraSystemPrompt):
47-
let service = ChatService()
48-
return try await service.processMessage(
49-
systemPrompt: nil,
50-
extraSystemPrompt: (useExtraSystemPrompt ?? false) ? extraSystemPrompt :
51-
nil,
52-
prompt: prompt
53-
)
54-
case let .customChat(systemPrompt, _):
55-
let service = ChatService()
56-
return try await service.processMessage(
57-
systemPrompt: systemPrompt,
58-
extraSystemPrompt: nil,
59-
prompt: prompt
60-
)
61-
case let .singleRoundDialog(
62-
systemPrompt,
63-
overwriteSystemPrompt,
64-
_,
65-
_
66-
):
67-
let service = ChatService()
68-
return try await service.handleSingleRoundDialogCommand(
69-
systemPrompt: systemPrompt,
70-
overwriteSystemPrompt: overwriteSystemPrompt ?? false,
71-
prompt: prompt
72-
)
73-
case let .promptToCode(extraSystemPrompt, instruction, _, _):
74-
let service = PromptToCodeService(
75-
code: prompt,
76-
selectionRange: .outOfScope,
77-
language: .plaintext,
78-
identSize: 4,
79-
usesTabsForIndentation: true,
80-
projectRootURL: .init(fileURLWithPath: "/"),
81-
fileURL: .init(fileURLWithPath: "/"),
82-
allCode: prompt,
83-
extraSystemPrompt: extraSystemPrompt,
84-
generateDescriptionRequirement: false
85-
)
86-
try await service.modifyCode(prompt: instruction ?? "Modify content.")
87-
return service.code
88-
}
89-
}
90-
)), title: BrowserChatTab.name),
28+
folderIfNeeded(
29+
BrowserChatTab.chatBuilders(
30+
externalDependency: externalDependenciesForBrowserChatTab()
31+
),
32+
title: BrowserChatTab.name
33+
),
9134
].compactMap { $0 }
9235

9336
return collection
9437
}
38+
39+
static func externalDependenciesForBrowserChatTab() -> BrowserChatTab.ExternalDependency {
40+
.init(
41+
getEditorContent: {
42+
guard let editor = XcodeInspector.shared.focusedEditor else {
43+
return .init(selectedText: "", language: "", fileContent: "")
44+
}
45+
let content = editor.content
46+
return .init(
47+
selectedText: content.selectedContent,
48+
language: languageIdentifierFromFileURL(
49+
XcodeInspector.shared
50+
.activeDocumentURL
51+
)
52+
.rawValue,
53+
fileContent: content.content
54+
)
55+
},
56+
handleCustomCommand: { command, prompt in
57+
switch command.feature {
58+
case let .chatWithSelection(extraSystemPrompt, _, useExtraSystemPrompt):
59+
let service = ChatService()
60+
return try await service.processMessage(
61+
systemPrompt: nil,
62+
extraSystemPrompt: (useExtraSystemPrompt ?? false) ? extraSystemPrompt :
63+
nil,
64+
prompt: prompt
65+
)
66+
case let .customChat(systemPrompt, _):
67+
let service = ChatService()
68+
return try await service.processMessage(
69+
systemPrompt: systemPrompt,
70+
extraSystemPrompt: nil,
71+
prompt: prompt
72+
)
73+
case let .singleRoundDialog(
74+
systemPrompt,
75+
overwriteSystemPrompt,
76+
_,
77+
_
78+
):
79+
let service = ChatService()
80+
return try await service.handleSingleRoundDialogCommand(
81+
systemPrompt: systemPrompt,
82+
overwriteSystemPrompt: overwriteSystemPrompt ?? false,
83+
prompt: prompt
84+
)
85+
case let .promptToCode(extraSystemPrompt, instruction, _, _):
86+
let service = PromptToCodeService(
87+
code: prompt,
88+
selectionRange: .outOfScope,
89+
language: .plaintext,
90+
identSize: 4,
91+
usesTabsForIndentation: true,
92+
projectRootURL: .init(fileURLWithPath: "/"),
93+
fileURL: .init(fileURLWithPath: "/"),
94+
allCode: prompt,
95+
extraSystemPrompt: extraSystemPrompt,
96+
generateDescriptionRequirement: false
97+
)
98+
try await service.modifyCode(prompt: instruction ?? "Modify content.")
99+
return service.code
100+
}
101+
}
102+
)
103+
}
95104
}
96105

97106
#else

Core/Sources/Service/GUI/GraphicalUserInterfaceController.swift

Lines changed: 41 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ import Environment
77
import Preferences
88
import SuggestionWidget
99

10+
#if canImport(ProChatTabs)
11+
import ProChatTabs
12+
#endif
13+
1014
#if canImport(ChatTabPersistent)
1115
import ChatTabPersistent
1216
#endif
@@ -33,6 +37,7 @@ struct GUI: ReducerProtocol {
3337
}
3438

3539
enum Action {
40+
case start
3641
case openChatPanel(forceDetach: Bool)
3742
case createChatGPTChatTabIfNeeded
3843
case sendCustomCommandToActiveChat(CustomCommand)
@@ -92,6 +97,13 @@ struct GUI: ReducerProtocol {
9297

9398
Reduce { state, action in
9499
switch action {
100+
case .start:
101+
return .run { send in
102+
#if canImport(ChatTabPersistent)
103+
await send(.persistent(.restoreChatTabs))
104+
#endif
105+
}
106+
95107
case let .openChatPanel(forceDetach):
96108
return .run { send in
97109
await send(
@@ -205,8 +217,10 @@ public final class GraphicalUserInterfaceController {
205217
dependencies.chatTabPool = chatTabPool
206218
dependencies.chatTabBuilderCollection = ChatTabFactory.chatTabBuilderCollection
207219

208-
#if canImport(ChatTabPersistent) && canImport(ProChatTab)
209-
dependencies.restoreChatTabInPool = chatTabPool.restore
220+
#if canImport(ChatTabPersistent) && canImport(ProChatTabs)
221+
dependencies.restoreChatTabInPool = {
222+
await chatTabPool.restore($0)
223+
}
210224
#endif
211225
}
212226
let store = StoreOf<GUI>(
@@ -253,6 +267,8 @@ public final class GraphicalUserInterfaceController {
253267
await commandHandler.handleCustomCommand(command)
254268
}
255269
}
270+
271+
store.send(.start)
256272
}
257273

258274
public func openGlobalChat() {
@@ -266,9 +282,10 @@ public final class GraphicalUserInterfaceController {
266282
extension ChatTabPool {
267283
@MainActor
268284
func createTab(
285+
id: String = UUID().uuidString,
269286
from builder: ChatTabBuilder
270287
) async -> (any ChatTab, ChatTabInfo)? {
271-
let id = UUID().uuidString
288+
let id = id
272289
let info = ChatTabInfo(id: id, title: "")
273290
guard let chatTap = await builder.build(store: createStore(id)) else { return nil }
274291
setTab(chatTap)
@@ -292,34 +309,40 @@ extension ChatTabPool {
292309
return (chatTap, info)
293310
}
294311

295-
#if canImport(ChatTabPersistent) && canImport(ProChatTab)
312+
#if canImport(ChatTabPersistent) && canImport(ProChatTabs)
296313
@MainActor
297314
func restore(
298315
_ data: ChatTabPersistent.RestorableTabData
299-
) async throws -> (any ChatTab, ChatTabInfo)? {
300-
let info = ChatTabInfo(id: data.id, title: "")
301-
302-
let chatTapTypes: [any ChatTab.Type] = [
303-
ChatGPTChatTab.self,
304-
BrowserChatTab.self,
305-
EmptyChatTab.self
306-
]
307-
308-
for type in chatTapTypes {
309-
guard data.name == type.name else { continue }
316+
) async -> (any ChatTab, ChatTabInfo)? {
317+
switch data.name {
318+
case ChatGPTChatTab.name:
310319
guard let builder = try? await ChatGPTChatTab.restore(
311320
from: data.data,
312321
externalDependency: ()
313322
) else { break }
314-
return createTab(from: builder)
323+
return await createTab(id: data.id, from: builder)
324+
case EmptyChatTab.name:
325+
guard let builder = try? await EmptyChatTab.restore(
326+
from: data.data,
327+
externalDependency: ()
328+
) else { break }
329+
return await createTab(id: data.id, from: builder)
330+
case BrowserChatTab.name:
331+
guard let builder = try? BrowserChatTab.restore(
332+
from: data.data,
333+
externalDependency: ChatTabFactory.externalDependenciesForBrowserChatTab()
334+
) else { break }
335+
return await createTab(id: data.id, from: builder)
336+
default:
337+
break
315338
}
316-
339+
317340
guard let builder = try? await EmptyChatTab.restore(
318341
from: data.data, externalDependency: ()
319342
) else {
320343
return nil
321344
}
322-
return createTab(for: builder)
345+
return await createTab(from: builder)
323346
}
324347
#endif
325348
}

Pro

Submodule Pro updated from 18b9066 to 0a25da7

0 commit comments

Comments
 (0)