commit bf7a913
Angus Gibson
·
2024-10-10 04:44:34 +0000 UTC
parent 17006ee
Show members with latest messages first in member completion Fixes: https://todo.sr.ht/~delthas/senpai/139
4 files changed,
+66,
-25
M
app.go
+1,
-1
1@@ -216,7 +216,7 @@ func NewApp(cfg Config) (app *App, err error) {
2 }
3
4 func (app *App) Close() {
5- app.win.Exit() // tell all instances of app.ircLoop to stop when possible
6+ app.win.Exit() // tell all instances of app.ircLoop to stop when possible
7 app.events <- event{ // tell app.eventLoop to stop
8 src: "*",
9 content: nil,
+21,
-1
1@@ -4,12 +4,30 @@ import (
2 "fmt"
3 "os"
4 "path/filepath"
5+ "sort"
6 "strings"
7
8 "git.sr.ht/~delthas/senpai/irc"
9 "git.sr.ht/~delthas/senpai/ui"
10 )
11
12+type members []irc.Member
13+
14+func (m members) Len() int {
15+ return len(m)
16+}
17+
18+func (m members) Less(i, j int) bool {
19+ if c := m[i].LastActive.Compare(m[j].LastActive); c != 0 {
20+ return c > 0
21+ }
22+ return strings.ToLower(m[i].Name.Name) < strings.ToLower(m[j].Name.Name)
23+}
24+
25+func (m members) Swap(i, j int) {
26+ m[i], m[j] = m[j], m[i]
27+}
28+
29 type completionAsync func(e irc.Event) []ui.Completion
30
31 func (app *App) completionsChannelMembers(cs []ui.Completion, cursorIdx int, text []rune) []ui.Completion {
32@@ -27,7 +45,9 @@ func (app *App) completionsChannelMembers(cs []ui.Completion, cursorIdx int, tex
33 netID, buffer := app.win.CurrentBuffer()
34 s := app.sessions[netID] // is not nil
35 wordCf := s.Casemap(string(word))
36- for _, name := range s.Names(buffer) {
37+ names := members(s.Names(buffer))
38+ sort.Sort(names)
39+ for _, name := range names {
40 if strings.HasPrefix(s.Casemap(name.Name.Name), wordCf) {
41 nickComp := []rune(name.Name.Name)
42 if start == 0 {
+43,
-23
1@@ -90,14 +90,19 @@ type User struct {
2 Disconnected bool // can only be true for monitored users.
3 }
4
5+type ChannelMember struct {
6+ Membership string
7+ LastActive time.Time
8+}
9+
10 // Channel is a joined channel.
11 type Channel struct {
12- Name string // the name of the channel.
13- Members map[*User]string // the set of members associated with their membership.
14- Topic string // the topic of the channel, or "" if absent.
15- TopicWho *Prefix // the name of the last user who set the topic.
16- TopicTime time.Time // the last time the topic has been changed.
17- Read time.Time // the time until which messages were read.
18+ Name string // the name of the channel.
19+ Members map[*User]ChannelMember // the set of members associated with their membership.
20+ Topic string // the topic of the channel, or "" if absent.
21+ TopicWho *Prefix // the name of the last user who set the topic.
22+ TopicTime time.Time // the last time the topic has been changed.
23+ Read time.Time // the time until which messages were read.
24 Pinned bool
25 Muted bool
26
27@@ -304,13 +309,14 @@ func (s *Session) Names(target string) []Member {
28 if s.IsChannel(target) {
29 if c, ok := s.channels[s.Casemap(target)]; ok {
30 names = make([]Member, 0, len(c.Members))
31- for u, pl := range c.Members {
32+ for u, m := range c.Members {
33 names = append(names, Member{
34- PowerLevel: pl,
35+ PowerLevel: m.Membership,
36 Name: u.Name.Copy(),
37 Away: u.Away,
38 Disconnected: u.Disconnected,
39 Self: s.nickCf == s.casemap(u.Name.Name),
40+ LastActive: m.LastActive,
41 })
42 }
43 }
44@@ -948,7 +954,7 @@ func (s *Session) handleMessageRegistered(msg Message, playback bool) (Event, er
45 if s.IsMe(nickCf) {
46 s.channels[channelCf] = Channel{
47 Name: msg.Params[0],
48- Members: map[*User]string{},
49+ Members: map[*User]ChannelMember{},
50 }
51 if _, ok := s.enabledCaps["away-notify"]; ok {
52 // Only try to know who is away if the list is
53@@ -960,7 +966,7 @@ func (s *Session) handleMessageRegistered(msg Message, playback bool) (Event, er
54 if _, ok := s.users[nickCf]; !ok {
55 s.users[nickCf] = &User{Name: msg.Prefix.Copy()}
56 }
57- c.Members[s.users[nickCf]] = ""
58+ c.Members[s.users[nickCf]] = ChannelMember{}
59 return UserJoinEvent{
60 User: msg.Prefix.Name,
61 Channel: c.Name,
62@@ -1136,7 +1142,9 @@ func (s *Session) handleMessageRegistered(msg Message, playback bool) (Event, er
63 if _, ok := s.users[nickCf]; !ok {
64 s.users[nickCf] = &User{Name: name.Name.Copy()}
65 }
66- c.Members[s.users[nickCf]] = name.PowerLevel
67+ m := c.Members[s.users[nickCf]]
68+ m.Membership = name.PowerLevel
69+ c.Members[s.users[nickCf]] = m
70 }
71
72 s.channels[channelCf] = c
73@@ -1262,23 +1270,24 @@ func (s *Session) handleMessageRegistered(msg Message, playback bool) (Event, er
74 }
75 nickCf := s.Casemap(change.Param)
76 user := s.users[nickCf]
77- membership, ok := c.Members[user]
78+ m, ok := c.Members[user]
79 if !ok {
80 continue
81 }
82 var newMembership []byte
83 if change.Enable {
84- newMembership = append([]byte(membership), s.prefixSymbols[i])
85+ newMembership = append([]byte(m.Membership), s.prefixSymbols[i])
86 sort.Slice(newMembership, func(i, j int) bool {
87 i = strings.IndexByte(s.prefixSymbols, newMembership[i])
88 j = strings.IndexByte(s.prefixSymbols, newMembership[j])
89 return i < j
90 })
91- } else if j := strings.IndexByte(membership, s.prefixSymbols[i]); j >= 0 {
92- newMembership = []byte(membership)
93+ } else if j := strings.IndexByte(m.Membership, s.prefixSymbols[i]); j >= 0 {
94+ newMembership = []byte(m.Membership)
95 newMembership = append(newMembership[:j], newMembership[j+1:]...)
96 }
97- c.Members[user] = string(newMembership)
98+ m.Membership = string(newMembership)
99+ c.Members[user] = m
100 }
101 s.channels[channelCf] = c
102 return ModeChangeEvent{
103@@ -1325,15 +1334,26 @@ func (s *Session) handleMessageRegistered(msg Message, playback bool) (Event, er
104 return nil, err
105 }
106
107- if playback {
108- return s.newMessageEvent(msg)
109- }
110-
111 targetCf := s.casemap(target)
112 nickCf := s.casemap(msg.Prefix.Name)
113- s.typings.Done(targetCf, nickCf)
114-
115- return s.newMessageEvent(msg)
116+ if !playback {
117+ s.typings.Done(targetCf, nickCf)
118+ }
119+ ev, err := s.newMessageEvent(msg)
120+ if err != nil {
121+ return nil, err
122+ }
123+ if c, ok := s.channels[targetCf]; ok {
124+ if u, ok := s.users[nickCf]; ok {
125+ if m, ok := c.Members[u]; ok {
126+ if ev.Time.After(m.LastActive) {
127+ m.LastActive = ev.Time
128+ c.Members[u] = m
129+ }
130+ }
131+ }
132+ }
133+ return ev, nil
134 case "TAGMSG":
135 if playback {
136 return nil, nil
+1,
-0
1@@ -467,6 +467,7 @@ type Member struct {
2 Away bool
3 Disconnected bool
4 Self bool // Added by senpai
5+ LastActive time.Time
6 }
7
8 type members struct {