Skip to content

Commit 2182f99

Browse files
authored
fix: use ai to determine memory injection (#53)
1 parent e2a664f commit 2182f99

72 files changed

Lines changed: 16593 additions & 13697 deletions

File tree

Some content is hidden

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

MobileUnitTestPlan.xctestplan

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
{
2+
"configurations" : [
3+
{
4+
"id" : "B1A2C3D4-0003-0003-0003-000000000003",
5+
"name" : "Mobile Unit",
6+
"options" : {
7+
8+
}
9+
}
10+
],
11+
"defaultOptions" : {
12+
"codeCoverage" : false,
13+
"testTimeoutsEnabled" : true
14+
},
15+
"testTargets" : [
16+
{
17+
"target" : {
18+
"containerPath" : "container:RxCode.xcodeproj",
19+
"identifier" : "DF230B5E2FBC7368008929A6",
20+
"name" : "RxCodeMobileTests"
21+
}
22+
}
23+
],
24+
"version" : 1
25+
}

Packages/Sources/MessageList/MessageList.swift

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -202,15 +202,23 @@ public struct MessageList<Message: MessageListItem, RowContent: View>: View {
202202
}
203203

204204
private var pinTailSpacerHeight: CGFloat {
205-
guard pinning.pinnedUserMessageID != nil, scrollViewHeight > 0 else { return 0 }
206-
let turnHeight = max(activeTurnMaxMeasuredHeight, rawActiveTurnMeasuredHeight)
207-
return max(0, scrollViewHeight - turnHeight - 16)
205+
guard pinning.isPinningUserMessage, scrollViewHeight > 0 else { return 0 }
206+
return max(0, scrollViewHeight - activeTurnHeight - MessageListConstants.minimumPinnedTailSpacing)
208207
}
209208

210209
private var rawActiveTurnMeasuredHeight: CGFloat {
211210
max(0, tailMarkerMinY - latestUserMinY)
212211
}
213212

213+
private var activeTurnHeight: CGFloat {
214+
max(activeTurnMaxMeasuredHeight, rawActiveTurnMeasuredHeight)
215+
}
216+
217+
private var pinnedTurnFillsViewport: Bool {
218+
guard scrollViewHeight > 0 else { return false }
219+
return activeTurnHeight >= scrollViewHeight - MessageListConstants.minimumPinnedTailSpacing
220+
}
221+
214222
private var isAnchoredAtBottom: Bool {
215223
anchor.isNearBottom && isAtBottom
216224
}
@@ -223,6 +231,22 @@ public struct MessageList<Message: MessageListItem, RowContent: View>: View {
223231
messages.last { $0.isUserMessage }?.id
224232
}
225233

234+
private var hasContentAfterPinnedUserMessage: Bool {
235+
guard let pinnedID = pinning.pinnedUserMessageID,
236+
let pinnedIndex = messages.firstIndex(where: { $0.id == pinnedID })
237+
else { return false }
238+
239+
let nextIndex = messages.index(after: pinnedIndex)
240+
guard nextIndex < messages.endIndex else { return false }
241+
return messages[nextIndex...].contains { !$0.isMessageListAccessory }
242+
}
243+
244+
private var shouldReleasePinnedUserMessageForFilledTurn: Bool {
245+
pinning.isPinningUserMessage
246+
&& hasContentAfterPinnedUserMessage
247+
&& pinnedTurnFillsViewport
248+
}
249+
226250
private var messageListChangeToken: MessageListChangeToken<Message.ID> {
227251
MessageListChangeToken(
228252
ids: messages.map(\.id),
@@ -237,6 +261,11 @@ public struct MessageList<Message: MessageListItem, RowContent: View>: View {
237261
visibleMaxY: metrics.visibleMaxY
238262
)
239263
updateIsAtBottomBinding(anchor.isNearBottom)
264+
265+
if shouldReleasePinnedUserMessageForFilledTurn, !isUserDrivenScroll {
266+
releasePinnedUserMessage(proxy: proxy)
267+
}
268+
240269
if decision == .scrollToBottom,
241270
isAtBottom,
242271
isStreaming,
@@ -426,7 +455,7 @@ public struct MessageList<Message: MessageListItem, RowContent: View>: View {
426455
}
427456

428457
private func updateActiveTurnMaxMeasuredHeight() {
429-
guard pinning.pinnedUserMessageID != nil else { return }
458+
guard pinning.isPinningUserMessage else { return }
430459
let measured = rawActiveTurnMeasuredHeight
431460
guard measured > activeTurnMaxMeasuredHeight + 0.5 else { return }
432461
var transaction = Transaction()
@@ -492,6 +521,7 @@ private nonisolated enum MessageListConstants {
492521
static let tailMarkerID = "message-list-tail-marker"
493522
static let coordinateSpaceName = "message-list-content"
494523
static let loadThreshold: CGFloat = 96
524+
static let minimumPinnedTailSpacing: CGFloat = 16
495525
static let userScrollDownDelta: CGFloat = 4
496526
static let layoutSettleDelayNanoseconds: UInt64 = 16_000_000
497527
static let streamingBottomScrollInterval: TimeInterval = 2

Packages/Sources/RxCodeChatKit/ChangeDiffView.swift

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,9 @@ public struct ChangeDiffView: View {
4343
@ViewBuilder
4444
private func unifiedRows(_ diff: String) -> some View {
4545
let lines = diff.components(separatedBy: .newlines)
46-
ForEach(Array(lines.enumerated()), id: \.offset) { _, line in
46+
ForEach(Array(lines.enumerated()), id: \.offset) { index, line in
4747
diffRow(
48+
lineNumber: unifiedLineNumber(line: line, offset: index),
4849
text: line.isEmpty ? " " : line,
4950
color: unifiedColor(line),
5051
background: unifiedBackground(line)
@@ -66,27 +67,42 @@ public struct ChangeDiffView: View {
6667
let added = hunk.newString
6768
.components(separatedBy: .newlines)
6869
.map { ("+ " + $0, ClaudeTheme.statusSuccess, ClaudeTheme.statusSuccess.opacity(0.06)) }
69-
ForEach(Array((removed + added).enumerated()), id: \.offset) { _, item in
70-
diffRow(text: item.0, color: item.1, background: item.2)
70+
ForEach(Array((removed + added).enumerated()), id: \.offset) { offset, item in
71+
diffRow(lineNumber: offset + 1, text: item.0, color: item.1, background: item.2)
7172
}
7273
}
7374
}
7475

7576
// MARK: - Shared row
7677

77-
private func diffRow(text: String, color: Color, background: Color) -> some View {
78-
ChatTextContentView(
79-
text,
80-
size: ClaudeTheme.messageSize(12),
81-
design: .monospaced,
82-
color: color
83-
)
84-
.frame(maxWidth: .infinity, alignment: .leading)
78+
private func diffRow(lineNumber: Int? = nil, text: String, color: Color, background: Color) -> some View {
79+
HStack(alignment: .firstTextBaseline, spacing: 8) {
80+
Text(lineNumber.map(String.init) ?? "")
81+
.font(.system(size: ClaudeTheme.messageSize(11), design: .monospaced))
82+
.foregroundStyle(ClaudeTheme.textTertiary)
83+
.frame(width: 34, alignment: .trailing)
84+
.accessibilityIdentifier("diff-line-number")
85+
86+
ChatTextContentView(
87+
text,
88+
size: ClaudeTheme.messageSize(12),
89+
design: .monospaced,
90+
color: color
91+
)
92+
.frame(maxWidth: .infinity, alignment: .leading)
93+
}
8594
.padding(.horizontal, 8)
8695
.padding(.vertical, 1)
8796
.background(background)
8897
}
8998

99+
private func unifiedLineNumber(line: String, offset: Int) -> Int? {
100+
if line.hasPrefix("diff ") || line.hasPrefix("index ") || line.hasPrefix("---") || line.hasPrefix("+++") || line.hasPrefix("@@") {
101+
return nil
102+
}
103+
return offset + 1
104+
}
105+
90106
private func unifiedColor(_ line: String) -> Color {
91107
if line.hasPrefix("+"), !line.hasPrefix("+++") { return ClaudeTheme.statusSuccess }
92108
if line.hasPrefix("-"), !line.hasPrefix("---") { return ClaudeTheme.statusError }

0 commit comments

Comments
 (0)