Skip to content

Commit cd41739

Browse files
committed
Merge branch 'release/0.26.0'
2 parents 3a08d0e + f9d2241 commit cd41739

34 files changed

+567
-187
lines changed

Core/Package.swift

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ let isProIncluded: Bool = {
3838
return false
3939
}
4040
do {
41-
if let content = String(
42-
data: try Data(contentsOf: confURL),
41+
if let content = try String(
42+
data: Data(contentsOf: confURL),
4343
encoding: .utf8
4444
) {
4545
if content.hasPrefix("YES") {
@@ -98,6 +98,9 @@ let package = Package(
9898
url: "https://github.com/pointfreeco/swift-composable-architecture",
9999
from: "0.55.0"
100100
),
101+
// quick hack to support custom UserDefaults
102+
// https://github.com/sindresorhus/KeyboardShortcuts
103+
.package(url: "https://github.com/intitni/KeyboardShortcuts", branch: "main"),
101104
].pro,
102105
targets: [
103106
// MARK: - Main
@@ -134,6 +137,7 @@ let package = Package(
134137
.product(name: "AsyncAlgorithms", package: "swift-async-algorithms"),
135138
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
136139
.product(name: "Dependencies", package: "swift-dependencies"),
140+
.product(name: "KeyboardShortcuts", package: "KeyboardShortcuts"),
137141
].pro([
138142
"ProService",
139143
])
@@ -168,6 +172,7 @@ let package = Package(
168172
.product(name: "OpenAIService", package: "Tool"),
169173
.product(name: "Preferences", package: "Tool"),
170174
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
175+
.product(name: "KeyboardShortcuts", package: "KeyboardShortcuts"),
171176
].pro([
172177
"ProHostApp",
173178
])

Core/Sources/ChatContextCollectors/SystemInfoChatContextCollector/SystemInfoChatContextCollector.swift

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,12 @@ public final class SystemInfoChatContextCollector: ChatContextCollector {
1919
) -> ChatContext {
2020
return .init(
2121
systemPrompt: """
22-
Current Time: \(
23-
Self.dateFormatter.string(from: Date())
24-
) (You can use it to calculate time in another time zone)
25-
""",
22+
## System Info
23+
24+
Current Time: \(
25+
Self.dateFormatter.string(from: Date())
26+
) (You can use it to calculate time in another time zone)
27+
""",
2628
retrievedContent: [],
2729
functions: []
2830
)

Core/Sources/ChatGPTChatTab/ChatGPTChatTab.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,16 @@ public class ChatGPTChatTab: ChatTab {
4646
ChatTabItemView(chat: chat)
4747
}
4848

49+
public func buildIcon() -> any View {
50+
WithViewStore(chat, observe: \.isReceivingMessage) { viewStore in
51+
if viewStore.state {
52+
Image(systemName: "ellipsis.message")
53+
} else {
54+
Image(systemName: "message")
55+
}
56+
}
57+
}
58+
4959
public func buildMenu() -> any View {
5060
ChatContextMenu(store: chat.scope(state: \.chatMenu, action: Chat.Action.chatMenu))
5161
}
@@ -125,3 +135,4 @@ public class ChatGPTChatTab: ChatTab {
125135
}.store(in: &cancellable)
126136
}
127137
}
138+

Core/Sources/ChatGPTChatTab/ChatPanel.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,7 @@ struct ChatPanelMessages: View {
133133
.foregroundStyle(.secondary)
134134
.padding(4)
135135
}
136+
.keyboardShortcut(.downArrow, modifiers: [.command])
136137
.opacity(pinnedToBottom ? 0 : 1)
137138
.buttonStyle(.plain)
138139
.onChange(of: viewStore.state) { _ in

Core/Sources/ChatService/CustomCommandTemplateProcessor.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1+
import AppKit
12
import Foundation
23
import SuggestionModel
34
import XcodeInspector
45

5-
struct CustomCommandTemplateProcessor {
6-
func process(_ text: String) -> String {
6+
public struct CustomCommandTemplateProcessor {
7+
public init() {}
8+
9+
public func process(_ text: String) -> String {
710
let info = getEditorInformation()
811
let editorContent = info.editorContent
912
let updatedText = text
@@ -22,6 +25,10 @@ struct CustomCommandTemplateProcessor {
2225
of: "{{active_editor_file_name}}",
2326
with: info.documentURL?.lastPathComponent ?? ""
2427
)
28+
.replacingOccurrences(
29+
of: "{{clipboard}}",
30+
with: NSPasteboard.general.string(forType: .string) ?? ""
31+
)
2532
return updatedText
2633
}
2734

Core/Sources/ChatService/DynamicContextController.swift

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import ChatContextCollector
22
import Foundation
33
import OpenAIService
4-
import Parsing
54
import Preferences
65
import XcodeInspector
76

@@ -65,17 +64,17 @@ final class DynamicContextController {
6564
}
6665
return contexts
6766
}
68-
67+
6968
let extraSystemPrompt = contexts
7069
.map(\.systemPrompt)
7170
.filter { !$0.isEmpty }
72-
.joined(separator: "\n")
73-
71+
.joined(separator: "\n\n")
72+
7473
let contextPrompts = contexts
7574
.flatMap(\.retrievedContent)
7675
.filter { !$0.content.isEmpty }
7776
.sorted { $0.priority > $1.priority }
78-
77+
7978
let contextualSystemPrompt = """
8079
\(language.isEmpty ? "" : "You must always reply in \(language)")
8180
\(systemPrompt)\(extraSystemPrompt.isEmpty ? "" : "\n\(extraSystemPrompt)")
@@ -88,30 +87,8 @@ final class DynamicContextController {
8887

8988
extension DynamicContextController {
9089
static func parseScopes(_ prompt: inout String) -> Set<String> {
91-
guard !prompt.isEmpty else { return [] }
92-
do {
93-
let parser = Parse {
94-
"@"
95-
Many {
96-
Prefix { $0.isLetter }
97-
} separator: {
98-
"+"
99-
} terminator: {
100-
" "
101-
}
102-
Skip {
103-
Many {
104-
" "
105-
}
106-
}
107-
Rest()
108-
}
109-
let (scopes, rest) = try parser.parse(prompt)
110-
prompt = String(rest)
111-
return Set(scopes.map(String.init))
112-
} catch {
113-
return []
114-
}
90+
let parser = MessageScopeParser()
91+
return parser(&prompt)
11592
}
11693
}
11794

Core/Sources/HostApp/GeneralView.swift

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import Client
22
import ComposableArchitecture
3+
import KeyboardShortcuts
34
import LaunchAgentManager
45
import Preferences
56
import SwiftUI
@@ -224,6 +225,8 @@ struct GeneralSettingsView: View {
224225
var preferWidgetToStayInsideEditorWhenWidthGreaterThan
225226
@AppStorage(\.hideCircularWidget)
226227
var hideCircularWidget
228+
@AppStorage(\.showHideWidgetShortcutGlobally)
229+
var showHideWidgetShortcutGlobally
227230
}
228231

229232
@StateObject var settings = Settings()
@@ -286,6 +289,15 @@ struct GeneralSettingsView: View {
286289
Text("pt")
287290
}
288291

292+
KeyboardShortcuts.Recorder("Hotkey to Toggle Widgets", name: .showHideWidget) { _ in
293+
// It's not used in this app!
294+
KeyboardShortcuts.disable(.showHideWidget)
295+
}
296+
297+
Toggle(isOn: $settings.showHideWidgetShortcutGlobally) {
298+
Text("Enable the Hotkey Globally")
299+
}
300+
289301
Toggle(isOn: $settings.hideCircularWidget) {
290302
Text("Hide circular widget")
291303
}
@@ -342,7 +354,7 @@ struct LargeIconPicker<
342354
}
343355
}
344356
}
345-
357+
346358
var body: some View {
347359
if #available(macOS 13.0, *) {
348360
LabeledContent {

Core/Sources/HostApp/HostApp.swift

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,16 @@
11
import Client
22
import ComposableArchitecture
33
import Foundation
4+
import KeyboardShortcuts
45

56
#if canImport(LicenseManagement)
67
import LicenseManagement
78
#endif
89

10+
extension KeyboardShortcuts.Name {
11+
static let showHideWidget = Self("ShowHideWidget")
12+
}
13+
914
struct HostApp: ReducerProtocol {
1015
struct State: Equatable {
1116
var general = General.State()
@@ -22,16 +27,20 @@ struct HostApp: ReducerProtocol {
2227
}
2328

2429
@Dependency(\.toast) var toast
30+
31+
init() {
32+
KeyboardShortcuts.userDefaults = .shared
33+
}
2534

2635
var body: some ReducerProtocol<State, Action> {
2736
Scope(state: \.general, action: /Action.general) {
2837
General()
2938
}
30-
39+
3140
Scope(state: \.chatModelManagement, action: /Action.chatModelManagement) {
3241
ChatModelManagement()
3342
}
34-
43+
3544
Scope(state: \.embeddingModelManagement, action: /Action.embeddingModelManagement) {
3645
EmbeddingModelManagement()
3746
}
@@ -40,7 +49,7 @@ struct HostApp: ReducerProtocol {
4049
switch action {
4150
case .appear:
4251
return .none
43-
52+
4453
case .informExtensionServiceAboutLicenseKeyChange:
4554
#if canImport(LicenseManagement)
4655
return .run { _ in
@@ -55,13 +64,13 @@ struct HostApp: ReducerProtocol {
5564
#else
5665
return .none
5766
#endif
58-
67+
5968
case .general:
6069
return .none
61-
70+
6271
case .chatModelManagement:
6372
return .none
64-
73+
6574
case .embeddingModelManagement:
6675
return .none
6776
}
@@ -70,8 +79,8 @@ struct HostApp: ReducerProtocol {
7079
}
7180

7281
import Dependencies
73-
import Preferences
7482
import Keychain
83+
import Preferences
7584

7685
struct UserDefaultsDependencyKey: DependencyKey {
7786
static var liveValue: UserDefaultsType = UserDefaults.shared
@@ -80,6 +89,7 @@ struct UserDefaultsDependencyKey: DependencyKey {
8089
it.removePersistentDomain(forName: "HostAppPreview")
8190
return it
8291
}()
92+
8393
static var testValue: UserDefaultsType = {
8494
let it = UserDefaults(suiteName: "HostAppTest")!
8595
it.removePersistentDomain(forName: "HostAppTest")
@@ -106,3 +116,4 @@ extension DependencyValues {
106116
set { self[APIKeyKeychainDependencyKey.self] = newValue }
107117
}
108118
}
119+

Core/Sources/Service/GUI/ChatTabFactory.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ enum ChatTabFactory {
3131
),
3232
title: BrowserChatTab.name
3333
),
34+
folderIfNeeded(TerminalChatTab.chatBuilders(), title: TerminalChatTab.name),
3435
].compactMap { $0 }
3536

3637
return collection

Core/Sources/Service/GUI/GraphicalUserInterfaceController.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,12 @@ extension ChatTabPool {
388388
externalDependency: ChatTabFactory.externalDependenciesForBrowserChatTab()
389389
) else { break }
390390
return await createTab(id: data.id, from: builder)
391+
case TerminalChatTab.name:
392+
guard let builder = try? await TerminalChatTab.restore(
393+
from: data.data,
394+
externalDependency: ()
395+
) else { break }
396+
return await createTab(id: data.id, from: builder)
391397
default:
392398
break
393399
}
@@ -397,7 +403,7 @@ extension ChatTabPool {
397403
) else {
398404
return nil
399405
}
400-
return await createTab(from: builder)
406+
return await createTab(id: data.id, from: builder)
401407
}
402408
#endif
403409
}

0 commit comments

Comments
 (0)