@@ -53,6 +53,10 @@ import (
53 "github.com/charmbracelet/x/editor"
53 "github.com/charmbracelet/x/editor"
56+// MouseScrollThreshold defines how many lines to scroll the chat when a mouse
57+// wheel event occurs.
58+const MouseScrollThreshold = 5
56// Compact mode breakpoints.
60// Compact mode breakpoints.
58 compactModeWidthBreakpoint = 120
62 compactModeWidthBreakpoint = 120
@@ -661,7 +665,7 @@ func (m *UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
661 case uiChat:
665 case uiChat:
662 switch msg.Button {
666 switch msg.Button {
663 case tea.MouseWheelUp:
667 case tea.MouseWheelUp:
664− if cmd := m.chat.ScrollByAndAnimate(-5); cmd != nil {
668+ if cmd := m.chat.ScrollByAndAnimate(-MouseScrollThreshold); cmd != nil {
665 cmds = append(cmds, cmd)
669 cmds = append(cmds, cmd)
667 if !m.chat.SelectedItemInView() {
671 if !m.chat.SelectedItemInView() {
@@ -671,7 +675,7 @@ func (m *UI) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
673 case tea.MouseWheelDown:
677 case tea.MouseWheelDown:
674− if cmd := m.chat.ScrollByAndAnimate(5); cmd != nil {
678+ if cmd := m.chat.ScrollByAndAnimate(MouseScrollThreshold); cmd != nil {
675 cmds = append(cmds, cmd)
679 cmds = append(cmds, cmd)
677 if !m.chat.SelectedItemInView() {
681 if !m.chat.SelectedItemInView() {
@@ -882,7 +886,6 @@ func (m *UI) loadNestedToolCalls(items []chat.MessageItem) {
882// if the message is a tool result it will update the corresponding tool call message
886// if the message is a tool result it will update the corresponding tool call message
883func (m *UI) appendSessionMessage(msg message.Message) tea.Cmd {
887func (m *UI) appendSessionMessage(msg message.Message) tea.Cmd {
884 var cmds []tea.Cmd
888 var cmds []tea.Cmd
885− atBottom := m.chat.list.AtBottom()
887 existing := m.chat.MessageItem(msg.ID)
890 existing := m.chat.MessageItem(msg.ID)
888 if existing != nil {
891 if existing != nil {
@@ -915,7 +918,7 @@ func (m *UI) appendSessionMessage(msg message.Message) tea.Cmd {
917 m.chat.AppendMessages(items...)
920 m.chat.AppendMessages(items...)
918− if atBottom {
921+ if m.chat.Follow() {
919 if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
922 if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
920 cmds = append(cmds, cmd)
923 cmds = append(cmds, cmd)
@@ -923,7 +926,7 @@ func (m *UI) appendSessionMessage(msg message.Message) tea.Cmd {
923 if msg.FinishPart() != nil && msg.FinishPart().Reason == message.FinishReasonEndTurn {
926 if msg.FinishPart() != nil && msg.FinishPart().Reason == message.FinishReasonEndTurn {
924 infoItem := chat.NewAssistantInfoItem(m.com.Styles, &msg, m.com.Config(), time.Unix(m.lastUserMessageTime, 0))
927 infoItem := chat.NewAssistantInfoItem(m.com.Styles, &msg, m.com.Config(), time.Unix(m.lastUserMessageTime, 0))
925 m.chat.AppendMessages(infoItem)
928 m.chat.AppendMessages(infoItem)
926− if atBottom {
929+ if m.chat.Follow() {
927 if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
930 if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
928 cmds = append(cmds, cmd)
931 cmds = append(cmds, cmd)
@@ -938,7 +941,7 @@ func (m *UI) appendSessionMessage(msg message.Message) tea.Cmd {
939 if toolMsgItem, ok := toolItem.(chat.ToolMessageItem); ok {
942 if toolMsgItem, ok := toolItem.(chat.ToolMessageItem); ok {
940 toolMsgItem.SetResult(&tr)
943 toolMsgItem.SetResult(&tr)
941− if atBottom {
944+ if m.chat.Follow() {
942 if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
945 if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
943 cmds = append(cmds, cmd)
946 cmds = append(cmds, cmd)
@@ -973,7 +976,6 @@ func (m *UI) handleClickFocus(msg tea.MouseClickMsg) (cmd tea.Cmd) {
973func (m *UI) updateSessionMessage(msg message.Message) tea.Cmd {
976func (m *UI) updateSessionMessage(msg message.Message) tea.Cmd {
974 var cmds []tea.Cmd
977 var cmds []tea.Cmd
975 existingItem := m.chat.MessageItem(msg.ID)
978 existingItem := m.chat.MessageItem(msg.ID)
976− atBottom := m.chat.list.AtBottom()
978 if existingItem != nil {
980 if existingItem != nil {
979 if assistantItem, ok := existingItem.(*chat.AssistantMessageItem); ok {
981 if assistantItem, ok := existingItem.(*chat.AssistantMessageItem); ok {
@@ -1022,7 +1024,7 @@ func (m *UI) updateSessionMessage(msg message.Message) tea.Cmd {
1024 m.chat.AppendMessages(items...)
1026 m.chat.AppendMessages(items...)
1025− if atBottom {
1027+ if m.chat.Follow() {
1026 if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
1028 if cmd := m.chat.ScrollToBottomAndAnimate(); cmd != nil {
1027 cmds = append(cmds, cmd)
1029 cmds = append(cmds, cmd)
@@ -1035,7 +1037,7 @@ func (m *UI) updateSessionMessage(msg message.Message) tea.Cmd {
1035func (m *UI) handleChildSessionMessage(event pubsub.Event[message.Message]) tea.Cmd {
1037func (m *UI) handleChildSessionMessage(event pubsub.Event[message.Message]) tea.Cmd {
1036 var cmds []tea.Cmd
1038 var cmds []tea.Cmd
1038− atBottom := m.chat.list.AtBottom()
1040+ atBottom := m.chat.AtBottom()
1039 // Only process messages with tool calls or results.
1041 // Only process messages with tool calls or results.
1040 if len(event.Payload.ToolCalls()) == 0 && len(event.Payload.ToolResults()) == 0 {
1042 if len(event.Payload.ToolCalls()) == 0 && len(event.Payload.ToolResults()) == 0 {
1041 return nil
1043 return nil