From 3c3c33e97810638645926668259ee4cccdc4dcbc Mon Sep 17 00:00:00 2001 From: Ayyan Date: Fri, 16 Jan 2026 18:02:34 -0500 Subject: [PATCH] feat(ui/chat): fetch older messages on select-scrolling (#716) --- internal/config/config.toml | 2 +- internal/ui/chat/guilds_tree.go | 7 ++++--- internal/ui/chat/messages_list.go | 35 +++++++++++++++++++++++++------ 3 files changed, 34 insertions(+), 10 deletions(-) diff --git a/internal/config/config.toml b/internal/config/config.toml index 7699484..22ef1fb 100644 --- a/internal/config/config.toml +++ b/internal/config/config.toml @@ -19,7 +19,7 @@ show_attachment_links = true # Note: Use autocomplete_limit = 0 to disable. autocomplete_limit = 20 -# The number of messages to fetch when a text-based channel is selected from guilds tree. The minimum and maximum value is 0 and 100, respectively. +# The number of messages to fetch when a text-based channel is selected from guilds tree. The minimum and maximum value is 1 and 100, respectively. messages_limit = 50 [timestamps] diff --git a/internal/ui/chat/guilds_tree.go b/internal/ui/chat/guilds_tree.go index 189c5e7..9ad8420 100644 --- a/internal/ui/chat/guilds_tree.go +++ b/internal/ui/chat/guilds_tree.go @@ -202,9 +202,10 @@ func (gt *guildsTree) onSelected(node *tview.TreeNode) { go gt.chatView.state.ReadState.MarkRead(channel.ID, channel.LastMessageID) - messages, err := gt.chatView.state.Messages(channel.ID, uint(gt.cfg.MessagesLimit)) + limit := gt.cfg.MessagesLimit + messages, err := gt.chatView.state.Messages(channel.ID, uint(limit)) if err != nil { - slog.Error("failed to get messages", "err", err, "channel_id", channel.ID, "limit", gt.cfg.MessagesLimit) + slog.Error("failed to get messages", "err", err, "channel_id", channel.ID, "limit", limit) return } @@ -218,7 +219,7 @@ func (gt *guildsTree) onSelected(node *tview.TreeNode) { gt.chatView.messagesList.reset() gt.chatView.messagesList.setTitle(*channel) - gt.chatView.messagesList.drawMessages(messages) + gt.chatView.messagesList.setMessages(messages) gt.chatView.messagesList.ScrollToEnd() hasNoPerm := channel.Type != discord.DirectMessage && channel.Type != discord.GroupDM && !gt.chatView.state.HasPermissions(channel.ID, discord.PermissionSendMessages) diff --git a/internal/ui/chat/messages_list.go b/internal/ui/chat/messages_list.go index 7ebbfa9..b851ec5 100644 --- a/internal/ui/chat/messages_list.go +++ b/internal/ui/chat/messages_list.go @@ -82,10 +82,8 @@ func (ml *messagesList) setTitle(channel discord.Channel) { ml.SetTitle(title) } -func (ml *messagesList) drawMessages(messages []discord.Message) { - ml.messages = slices.Grow(ml.messages[:0], len(messages)) - ml.messages = ml.messages[:len(messages)] - copy(ml.messages, messages) +func (ml *messagesList) setMessages(messages []discord.Message) { + ml.messages = slices.Clone(messages) slices.Reverse(ml.messages) } @@ -355,6 +353,33 @@ func (ml *messagesList) _select(name string) { cursor = len(messages) - 1 case cursor > 0: cursor-- + case cursor == 0: + selectedChannel := ml.chatView.SelectedChannel() + if selectedChannel == nil { + return + } + + channelID := selectedChannel.ID + before := ml.messages[0].ID + limit := uint(ml.cfg.MessagesLimit) + messages, err := ml.chatView.state.MessagesBefore(channelID, before, limit) + if err != nil { + slog.Error("failed to fetch older messages", "err", err) + return + } + if len(messages) == 0 { + return + } + + if guildID := selectedChannel.GuildID; guildID.IsValid() { + ml.requestGuildMembers(guildID, messages) + } + + older := slices.Clone(messages) + slices.Reverse(older) + + ml.messages = slices.Concat(older, ml.messages) + cursor = len(messages) - 1 } case ml.cfg.Keys.MessagesList.SelectNext: switch { @@ -379,8 +404,6 @@ func (ml *messagesList) _select(name string) { if refIdx != -1 { cursor = refIdx } - } else { - return } }