fix: do not scroll to bottom if user has scrolled up (#2049)

Andrey Nering created

Change summary

internal/ui/list/list.go |  4 +++-
internal/ui/model/ui.go  | 20 ++++++++++++++++----
2 files changed, 19 insertions(+), 5 deletions(-)

Detailed changes

internal/ui/list/list.go 🔗

@@ -77,6 +77,8 @@ func (l *List) Gap() int {
 
 // AtBottom returns whether the list is showing the last item at the bottom.
 func (l *List) AtBottom() bool {
+	const margin = 2
+
 	if len(l.items) == 0 {
 		return true
 	}
@@ -92,7 +94,7 @@ func (l *List) AtBottom() bool {
 		totalHeight += itemHeight
 	}
 
-	return totalHeight-l.offsetLine <= l.height
+	return totalHeight-l.offsetLine-margin <= l.height
 }
 
 // SetReverse shows the list in reverse order.

internal/ui/model/ui.go 🔗

@@ -830,11 +830,14 @@ func (m *UI) loadNestedToolCalls(items []chat.MessageItem) {
 // if the message is a tool result it will update the corresponding tool call message
 func (m *UI) appendSessionMessage(msg message.Message) tea.Cmd {
 	var cmds []tea.Cmd
+	atBottom := m.chat.list.AtBottom()
+
 	existing := m.chat.MessageItem(msg.ID)
 	if existing != nil {
 		// message already exists, skip
 		return nil
 	}
+
 	switch msg.Role {
 	case message.User:
 		m.lastUserMessageTime = msg.CreatedAt
@@ -860,14 +863,18 @@ func (m *UI) appendSessionMessage(msg message.Message) tea.Cmd {
 			}
 		}
 		m.chat.AppendMessages(items...)
-		if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
-			cmds = append(cmds, cmd)
+		if atBottom {
+			if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
+				cmds = append(cmds, cmd)
+			}
 		}
 		if msg.FinishPart() != nil && msg.FinishPart().Reason == message.FinishReasonEndTurn {
 			infoItem := chat.NewAssistantInfoItem(m.com.Styles, &msg, time.Unix(m.lastUserMessageTime, 0))
 			m.chat.AppendMessages(infoItem)
-			if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
-				cmds = append(cmds, cmd)
+			if atBottom {
+				if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
+					cmds = append(cmds, cmd)
+				}
 			}
 		}
 	case message.Tool:
@@ -879,6 +886,11 @@ func (m *UI) appendSessionMessage(msg message.Message) tea.Cmd {
 			}
 			if toolMsgItem, ok := toolItem.(chat.ToolMessageItem); ok {
 				toolMsgItem.SetResult(&tr)
+				if atBottom {
+					if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
+						cmds = append(cmds, cmd)
+					}
+				}
 			}
 		}
 	}