Skip to content

Commit bd0f17d

Browse files
committed
Merge branch 'release/0.28.0'
2 parents 58a685d + 8ccb85f commit bd0f17d

File tree

82 files changed

+4333
-1952
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

82 files changed

+4333
-1952
lines changed

Core/Package.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ let package = Package(
250250
.product(name: "OpenAIService", package: "Tool"),
251251
.product(name: "Logger", package: "Tool"),
252252
.product(name: "ChatTab", package: "Tool"),
253+
.product(name: "Terminal", package: "Tool"),
253254
.product(name: "MarkdownUI", package: "swift-markdown-ui"),
254255
.product(name: "ComposableArchitecture", package: "swift-composable-architecture"),
255256
]

Core/Sources/ChatGPTChatTab/Chat.swift

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,54 @@ import ComposableArchitecture
33
import Foundation
44
import OpenAIService
55
import Preferences
6+
import Terminal
67

7-
public struct ChatMessage: Equatable {
8-
public enum Role {
8+
public struct DisplayedChatMessage: Equatable {
9+
public enum Role: Equatable {
910
case user
1011
case assistant
1112
case function
1213
case ignored
1314
}
1415

16+
public struct Reference: Equatable {
17+
public var title: String
18+
public var subtitle: String
19+
public var uri: String
20+
public var startLine: Int?
21+
22+
public init(title: String, subtitle: String, uri: String, startLine: Int?) {
23+
self.title = title
24+
self.subtitle = subtitle
25+
self.uri = uri
26+
self.startLine = startLine
27+
}
28+
}
29+
1530
public var id: String
1631
public var role: Role
1732
public var text: String
33+
public var references: [Reference] = []
1834

19-
public init(id: String, role: Role, text: String) {
35+
public init(id: String, role: Role, text: String, references: [Reference]) {
2036
self.id = id
2137
self.role = role
2238
self.text = text
39+
self.references = references
2340
}
2441
}
2542

43+
private var isPreview: Bool {
44+
ProcessInfo.processInfo.environment["XCODE_RUNNING_FOR_PREVIEWS"] == "1"
45+
}
46+
2647
struct Chat: ReducerProtocol {
2748
public typealias MessageID = String
2849

2950
struct State: Equatable {
3051
var title: String = "Chat"
3152
@BindingState var typedMessage = ""
32-
var history: [ChatMessage] = []
53+
var history: [DisplayedChatMessage] = []
3354
@BindingState var isReceivingMessage = false
3455
var chatMenu = ChatMenu.State()
3556
@BindingState var focusedField: Field?
@@ -51,6 +72,7 @@ struct Chat: ReducerProtocol {
5172
case resendMessageButtonTapped(MessageID)
5273
case setAsExtraPromptButtonTapped(MessageID)
5374
case focusOnTextField
75+
case referenceClicked(DisplayedChatMessage.Reference)
5476

5577
case observeChatService
5678
case observeHistoryChange
@@ -77,8 +99,11 @@ struct Chat: ReducerProtocol {
7799
case observeSystemPromptChange(UUID)
78100
case observeExtraSystemPromptChange(UUID)
79101
case observeDefaultScopesChange(UUID)
102+
case sendMessage(UUID)
80103
}
81104

105+
@Dependency(\.openURL) var openURL
106+
82107
var body: some ReducerProtocol<State, Action> {
83108
BindingReducer()
84109

@@ -90,6 +115,7 @@ struct Chat: ReducerProtocol {
90115
switch action {
91116
case .appear:
92117
return .run { send in
118+
if isPreview { return }
93119
await send(.observeChatService)
94120
await send(.historyChanged)
95121
await send(.isReceivingMessageChanged)
@@ -104,16 +130,19 @@ struct Chat: ReducerProtocol {
104130
state.typedMessage = ""
105131
return .run { _ in
106132
try await service.send(content: message)
107-
}
133+
}.cancellable(id: CancelID.sendMessage(id))
108134

109135
case .returnButtonTapped:
110136
state.typedMessage += "\n"
111137
return .none
112138

113139
case .stopRespondingButtonTapped:
114-
return .run { _ in
115-
await service.stopReceivingMessage()
116-
}
140+
return .merge(
141+
.run { _ in
142+
await service.stopReceivingMessage()
143+
},
144+
.cancel(id: CancelID.sendMessage(id))
145+
)
117146

118147
case .clearButtonTap:
119148
return .run { _ in
@@ -134,7 +163,29 @@ struct Chat: ReducerProtocol {
134163
return .run { _ in
135164
await service.setMessageAsExtraPrompt(id: id)
136165
}
137-
166+
167+
case let .referenceClicked(reference):
168+
let fileURL = URL(fileURLWithPath: reference.uri)
169+
return .run { _ in
170+
if FileManager.default.fileExists(atPath: fileURL.path) {
171+
let terminal = Terminal()
172+
do {
173+
_ = try await terminal.runCommand(
174+
"/bin/bash",
175+
arguments: [
176+
"-c",
177+
"xed -l \(reference.startLine ?? 0) \"\(reference.uri)\"",
178+
],
179+
environment: [:]
180+
)
181+
} catch {
182+
print(error)
183+
}
184+
} else if let url = URL(string: reference.uri), url.scheme != nil {
185+
await openURL(url)
186+
}
187+
}
188+
138189
case .focusOnTextField:
139190
state.focusedField = .textField
140191
return .none
@@ -247,7 +298,15 @@ struct Chat: ReducerProtocol {
247298
case .function: return .function
248299
}
249300
}(),
250-
text: message.summary ?? message.content ?? ""
301+
text: message.summary ?? message.content ?? "",
302+
references: message.references.map {
303+
.init(
304+
title: $0.title,
305+
subtitle: $0.subTitle,
306+
uri: $0.uri,
307+
startLine: $0.startLine
308+
)
309+
}
251310
)
252311
}
253312

0 commit comments

Comments
 (0)