fix(messageslist): fetch older messages once as the cursor reaches the top

This commit is contained in:
ayn2op 2026-10-06 15:30:32 -04:00
parent fca6ea5c1d
commit c8b024eb0e
3 changed files with 28 additions and 12 deletions

View file

@ -842,6 +842,11 @@ func (ml Model) Update(msg tview.Msg) (Model, tview.Cmd) {
return ml, cmd
}
// atTop reports whether the oldest message shown is selected.
func (ml *Model) atTop() bool {
return ml.cursor() >= 0 && ml.cursor() == ml.messageIndex(-1, 1)
}
// update changes ml in response to msg and returns a command to run, or nil.
func (ml *Model) update(msg tview.Msg) tview.Cmd {
switch msg := msg.(type) {
@ -856,8 +861,7 @@ func (ml *Model) update(msg tview.Msg) tview.Cmd {
ml.selectDown()
return nil
case keybind.Matches(msg, ml.cfg.Keybinds.MessagesList.SelectTop.Keybind):
ml.selectTop()
return nil
return ml.selectTop()
case keybind.Matches(msg, ml.cfg.Keybinds.MessagesList.SelectBottom.Keybind):
ml.selectBottom()
return nil
@ -898,12 +902,8 @@ func (ml *Model) update(msg tview.Msg) tview.Cmd {
for i, message := range msg.Older {
older[i] = messageItem{message: message}
}
first := ml.messageIndex(-1, 1)
ml.items = slices.Concat(older, ml.items)
switch {
case prevCursor == first && len(older) > 0:
ml.setCursor(len(older) - 1)
case prevCursor >= 0:
if prevCursor >= 0 {
ml.setCursor(prevCursor + len(older))
}
ml.rebuildItems()
@ -943,8 +943,12 @@ func (ml *Model) update(msg tview.Msg) tview.Cmd {
ml.kitty = msg.Name == "kitty" || msg.Name == "ghostty"
}
case listMsg:
top := ml.atTop()
ml.selectionState.Apply(list.Change(msg))
ml.onRowCursorChanged(ml.cursor())
if !top && ml.atTop() {
return ml.fetchOlderMessages()
}
}
return nil
}
@ -957,8 +961,12 @@ func (ml *Model) selectDown() {
}
}
func (ml *Model) selectTop() {
func (ml *Model) selectTop() tview.Cmd {
if ml.atTop() {
return nil
}
ml.setCursor(ml.messageIndex(-1, 1))
return ml.fetchOlderMessages()
}
func (ml *Model) selectBottom() {

View file

@ -42,6 +42,13 @@ func TestModelBuildItem(t *testing.T) {
if ml.buildItem(ml.messageIndex(len(ml.items), -1)) != view {
t.Fatal("message view was not reused")
}
if ml.selectTop() == nil || ml.selectTop() != nil || ml.selectUp() != nil {
t.Fatal("older messages were not fetched once on reaching the top")
}
ml.selectBottom()
if _, cmd := ml.Update(listMsg{}); cmd == nil {
t.Fatal("clicking the top message did not fetch older messages")
}
ml.selectBottom()
*ml, _ = ml.Update(olderMessagesLoadedMsg{ChannelID: 1, Older: []discord.Message{{ID: 1}}})
selected, ok := ml.selectedMessage()
@ -127,8 +134,7 @@ func TestModelRebuildItems(t *testing.T) {
assertSelected(2)
*ml, _ = ml.Update(olderMessagesLoadedMsg{ChannelID: 1, Older: messages[2:]})
assertItems(1, 2, 3)
assertSelected(1)
ml.selectDown()
assertSelected(2)
ml.deleteMessage(ml.cursor())
assertItems(1, 3)
assertSelected(1)

View file

@ -53,8 +53,10 @@ func (ml *Model) selectUp() tview.Cmd {
ml.selectBottom()
} else if previous := ml.messageIndex(cursor, -1); previous >= 0 {
ml.setCursor(previous)
} else {
return ml.fetchOlderMessages()
// Older messages are fetched once as the cursor reaches the top, rather than on each key press there.
if ml.atTop() {
return ml.fetchOlderMessages()
}
}
return nil
}