Explorar o código

Fix chat auto-scroll to show assistant response from start

Keep user messages pinned to the bottom, but align new assistant replies to the top of the visible chat area so long responses open at their beginning instead of the end.

Co-authored-by: Cursor <cursoragent@cursor.com>
AhtashamShahzad1 hai 3 semanas
pai
achega
610f7979d7
Modificáronse 1 ficheiros con 27 adicións e 2 borrados
  1. 27 2
      App for Indeed/Views/DashboardView.swift

+ 27 - 2
App for Indeed/Views/DashboardView.swift

@@ -1564,9 +1564,16 @@ final class DashboardView: NSView, NSTextFieldDelegate {
1564
         }
1564
         }
1565
         DispatchQueue.main.async { [weak self] in
1565
         DispatchQueue.main.async { [weak self] in
1566
             guard let self else { return }
1566
             guard let self else { return }
1567
+            let scroll: () -> Void = {
1568
+                if isUser {
1569
+                    self.scrollChatToBottom()
1570
+                } else {
1571
+                    self.scrollChatToShowTopOfView(host)
1572
+                }
1573
+            }
1567
             if self.prefersReducedMotion {
1574
             if self.prefersReducedMotion {
1568
                 self.updateChatBubbleWidths()
1575
                 self.updateChatBubbleWidths()
1569
-                self.scrollChatToBottom()
1576
+                scroll()
1570
                 return
1577
                 return
1571
             }
1578
             }
1572
             NSAnimationContext.runAnimationGroup { ctx in
1579
             NSAnimationContext.runAnimationGroup { ctx in
@@ -1575,7 +1582,7 @@ final class DashboardView: NSView, NSTextFieldDelegate {
1575
                 host.animator().alphaValue = 1
1582
                 host.animator().alphaValue = 1
1576
             }
1583
             }
1577
             self.updateChatBubbleWidths()
1584
             self.updateChatBubbleWidths()
1578
-            self.scrollChatToBottom()
1585
+            scroll()
1579
         }
1586
         }
1580
     }
1587
     }
1581
 
1588
 
@@ -1746,6 +1753,24 @@ final class DashboardView: NSView, NSTextFieldDelegate {
1746
         chatScrollView.reflectScrolledClipView(chatScrollView.contentView)
1753
         chatScrollView.reflectScrolledClipView(chatScrollView.contentView)
1747
     }
1754
     }
1748
 
1755
 
1756
+    /// Scrolls so the top of `view` sits at the top of the chat clip (flipped document coords). Long assistant replies stay readable from the first line instead of jumping to the end.
1757
+    private func scrollChatToShowTopOfView(_ view: NSView) {
1758
+        chatDocumentView.layoutSubtreeIfNeeded()
1759
+        view.layoutSubtreeIfNeeded()
1760
+        let doc = chatDocumentView
1761
+        let visibleHeight = chatScrollView.contentView.bounds.height
1762
+        let docHeight = doc.bounds.height
1763
+        guard docHeight > 0, visibleHeight > 0 else {
1764
+            scrollChatToBottom()
1765
+            return
1766
+        }
1767
+        let rectInDoc = view.convert(view.bounds, to: doc)
1768
+        let maxY = max(0, docHeight - visibleHeight)
1769
+        let targetY = min(max(0, rectInDoc.minY), maxY)
1770
+        chatScrollView.contentView.scroll(to: NSPoint(x: 0, y: targetY))
1771
+        chatScrollView.reflectScrolledClipView(chatScrollView.contentView)
1772
+    }
1773
+
1749
     private func addInlineChatThinkingRow() {
1774
     private func addInlineChatThinkingRow() {
1750
         removeInlineChatThinkingRow()
1775
         removeInlineChatThinkingRow()
1751
         let host = NSView()
1776
         let host = NSView()