commit ca71c08

delthas  ·  2025-04-20 12:06:28 +0000 UTC
parent 9baf688
Support METADATA (pin/mute) for user buffers

Also, fix not monitoring users again after a reconnect in some
cases.

See: https://codeberg.org/emersion/soju/pulls/54
6 files changed,  +78, -73
M app.go
M app.go
+38, -33
  1@@ -793,13 +793,8 @@ func (app *App) handleMouseEvent(ev vaxis.Mouse) {
  2 					members := s.Names(target)
  3 					if i < len(members) {
  4 						buffer := members[i].Name.Name
  5-						i, added := app.win.AddBuffer(netID, "", buffer)
  6+						i, _ := app.addUserBuffer(netID, buffer, time.Time{})
  7 						app.win.JumpBufferIndex(i)
  8-						if added {
  9-							s.MonitorAdd(buffer)
 10-							s.ReadGet(buffer)
 11-							s.NewHistoryRequest(buffer).WithLimit(500).Latest()
 12-						}
 13 					}
 14 				}
 15 			}
 16@@ -980,13 +975,8 @@ func (app *App) handleNickEvent(ev *events.EventClickNick) {
 17 	if s == nil {
 18 		return
 19 	}
 20-	i, added := app.win.AddBuffer(ev.NetID, "", ev.Nick)
 21+	i, _ := app.addUserBuffer(ev.NetID, ev.Nick, time.Time{})
 22 	app.win.JumpBufferIndex(i)
 23-	if added {
 24-		s.MonitorAdd(ev.Nick)
 25-		s.ReadGet(ev.Nick)
 26-		s.NewHistoryRequest(ev.Nick).WithLimit(500).Latest()
 27-	}
 28 }
 29 
 30 func (app *App) handleChannelEvent(ev *events.EventClickChannel) {
 31@@ -1391,6 +1381,8 @@ func (app *App) handleIRCEvent(netID string, ev interface{}) {
 32 		}
 33 	case irc.SelfJoinEvent:
 34 		i, added := app.win.AddBuffer(netID, "", ev.Channel)
 35+		i = app.win.SetMuted(netID, ev.Channel, s.MutedGet(ev.Channel))
 36+		i = app.win.SetPinned(netID, ev.Channel, s.PinnedGet(ev.Channel))
 37 		if !ev.Read.IsZero() {
 38 			app.win.SetRead(netID, ev.Channel, ev.Read)
 39 		}
 40@@ -1418,8 +1410,6 @@ func (app *App) handleIRCEvent(netID string, ev interface{}) {
 41 			topic := ui.IRCString(ev.Topic).ParseURLs()
 42 			app.win.SetTopic(netID, ev.Channel, topic)
 43 		}
 44-		app.win.SetPinned(netID, ev.Channel, ev.Pinned)
 45-		app.win.SetMuted(netID, ev.Channel, ev.Muted)
 46 
 47 		// Restore last buffer
 48 		if netID == app.lastNetID && ev.Channel == app.lastBuffer {
 49@@ -1496,20 +1486,11 @@ func (app *App) handleIRCEvent(netID string, ev interface{}) {
 50 			break
 51 		}
 52 		if buffer != "" && !s.IsChannel(buffer) {
 53-			if _, added := app.win.AddBuffer(netID, "", buffer); added {
 54-				app.monitor[netID][buffer] = struct{}{}
 55-				s.MonitorAdd(buffer)
 56-				s.ReadGet(buffer)
 57-				if t, ok := msg.Time(); ok {
 58-					s.NewHistoryRequest(buffer).
 59-						WithLimit(500).
 60-						Before(t)
 61-				} else {
 62-					s.NewHistoryRequest(buffer).
 63-						WithLimit(500).
 64-						Latest()
 65-				}
 66+			t, ok := msg.Time()
 67+			if !ok {
 68+				t = time.Time{}
 69 			}
 70+			app.addUserBuffer(netID, buffer, t)
 71 		}
 72 		app.win.AddLine(netID, buffer, line)
 73 		if line.Notify == ui.NotifyHighlight {
 74@@ -1545,15 +1526,10 @@ func (app *App) handleIRCEvent(netID string, ev interface{}) {
 75 			if s.IsChannel(target.name) {
 76 				continue
 77 			}
 78-			s.MonitorAdd(target.name)
 79-			s.ReadGet(target.name)
 80-			app.win.AddBuffer(netID, "", target.name)
 81 			// CHATHISTORY BEFORE excludes its bound, so add 1ms
 82 			// (precision of the time tag) to include that last message.
 83 			target.last = target.last.Add(1 * time.Millisecond)
 84-			s.NewHistoryRequest(target.name).
 85-				WithLimit(500).
 86-				Before(target.last)
 87+			app.addUserBuffer(netID, target.name, target.last)
 88 		}
 89 	case irc.HistoryEvent:
 90 		var linesBefore []ui.Line
 91@@ -1620,6 +1596,9 @@ func (app *App) handleIRCEvent(netID string, ev interface{}) {
 92 	case irc.MetadataChangeEvent:
 93 		app.win.SetPinned(netID, ev.Target, ev.Pinned)
 94 		app.win.SetMuted(netID, ev.Target, ev.Muted)
 95+		if ev.Pinned && !s.IsChannel(ev.Target) {
 96+			app.addUserBuffer(netID, ev.Target, time.Time{})
 97+		}
 98 	case irc.BouncerNetworkEvent:
 99 		if !ev.Delete {
100 			_, added := app.win.AddBuffer(ev.ID, ev.Name, "")
101@@ -2333,6 +2312,32 @@ func (app *App) printTopic(netID, buffer string) (ok bool) {
102 	return true
103 }
104 
105+func (app *App) addUserBuffer(netID, buffer string, t time.Time) (i int, added bool) {
106+	i, added = app.win.AddBuffer(netID, "", buffer)
107+	if !added {
108+		return
109+	}
110+	s := app.sessions[netID]
111+	if s == nil {
112+		return
113+	}
114+	i = app.win.SetMuted(netID, buffer, s.MutedGet(buffer))
115+	i = app.win.SetPinned(netID, buffer, s.PinnedGet(buffer))
116+	app.monitor[netID][buffer] = struct{}{}
117+	s.MonitorAdd(buffer)
118+	s.ReadGet(buffer)
119+	if !t.IsZero() {
120+		s.NewHistoryRequest(buffer).
121+			WithLimit(500).
122+			Before(t)
123+	} else {
124+		s.NewHistoryRequest(buffer).
125+			WithLimit(500).
126+			Latest()
127+	}
128+	return
129+}
130+
131 func keyMatches(k vaxis.Key, r rune, mods vaxis.ModifierMask) bool {
132 	m := k.Modifiers
133 	m &^= vaxis.ModCapsLock
+2, -11
 1@@ -655,18 +655,13 @@ func commandDoQuery(app *App, args []string) (err error) {
 2 	if s.IsChannel(target) {
 3 		return fmt.Errorf("cannot query a channel, use JOIN instead")
 4 	}
 5-	i, added := app.win.AddBuffer(netID, "", target)
 6+	i, _ := app.addUserBuffer(netID, target, time.Time{})
 7 	app.win.JumpBufferIndex(i)
 8 	if len(args) > 1 {
 9 		if err := commandSendMessage(app, target, args[1]); err != nil {
10 			return err
11 		}
12 	}
13-	if added {
14-		s.MonitorAdd(target)
15-		s.ReadGet(target)
16-		s.NewHistoryRequest(target).WithLimit(200).Latest()
17-	}
18 	return nil
19 }
20 
21@@ -1041,12 +1036,8 @@ func commandSendMessage(app *App, target string, content string) error {
22 			Time:            time.Now(),
23 		})
24 		if buffer != "" && !s.IsChannel(target) {
25-			app.monitor[netID][buffer] = struct{}{}
26-			s.MonitorAdd(buffer)
27-			s.ReadGet(buffer)
28-			app.win.AddBuffer(netID, "", buffer)
29+			app.addUserBuffer(netID, buffer, time.Time{})
30 		}
31-
32 		app.win.AddLine(netID, buffer, line)
33 	}
34 	return nil
+0, -2
1@@ -32,8 +32,6 @@ type SelfJoinEvent struct {
2 	Requested bool // whether we recently requested to join that channel
3 	Topic     string
4 	Read      time.Time
5-	Pinned    bool
6-	Muted     bool
7 }
8 
9 type UserJoinEvent struct {
+26, -19
  1@@ -104,12 +104,15 @@ type Channel struct {
  2 	TopicWho  *Prefix                 // the name of the last user who set the topic.
  3 	TopicTime time.Time               // the last time the topic has been changed.
  4 	Read      time.Time               // the time until which messages were read.
  5-	Pinned    bool
  6-	Muted     bool
  7 
  8 	complete bool // whether this structure is fully initialized.
  9 }
 10 
 11+type Metadata struct {
 12+	Pinned bool
 13+	Muted  bool
 14+}
 15+
 16 // SessionParams defines how to connect to an IRC server.
 17 type SessionParams struct {
 18 	Nickname string
 19@@ -156,6 +159,7 @@ type Session struct {
 20 
 21 	users          map[string]*User        // known users.
 22 	channels       map[string]Channel      // joined channels.
 23+	metadata       map[string]Metadata     // known target metadata.
 24 	chBatches      map[string]HistoryEvent // channel history batches being processed.
 25 	chReqs         map[string]struct{}     // set of targets for which history is currently requested.
 26 	targetsBatchID string                  // ID of the channel history targets batch being processed.
 27@@ -193,6 +197,7 @@ func NewSession(out chan<- Message, params SessionParams) *Session {
 28 		prefixModes:     "ov",
 29 		users:           map[string]*User{},
 30 		channels:        map[string]Channel{},
 31+		metadata:        map[string]Metadata{},
 32 		chBatches:       map[string]HistoryEvent{},
 33 		chReqs:          map[string]struct{}{},
 34 		monitors:        map[string]struct{}{},
 35@@ -568,6 +573,10 @@ func (s *Session) ReadSet(target string, timestamp time.Time) {
 36 	}
 37 }
 38 
 39+func (s *Session) MutedGet(target string) bool {
 40+	return s.metadata[s.Casemap(target)].Muted
 41+}
 42+
 43 func (s *Session) MutedSet(target string, muted bool) (ok bool) {
 44 	var v string
 45 	if muted {
 46@@ -582,6 +591,10 @@ func (s *Session) MutedSet(target string, muted bool) (ok bool) {
 47 	return
 48 }
 49 
 50+func (s *Session) PinnedGet(target string) bool {
 51+	return s.metadata[s.Casemap(target)].Pinned
 52+}
 53+
 54 func (s *Session) PinnedSet(target string, pinned bool) (ok bool) {
 55 	var v string
 56 	if pinned {
 57@@ -1185,8 +1198,6 @@ func (s *Session) handleMessageRegistered(msg Message, playback bool) (Event, er
 58 				Channel: c.Name,
 59 				Topic:   c.Topic,
 60 				Read:    c.Read,
 61-				Pinned:  c.Pinned,
 62-				Muted:   c.Muted,
 63 			}
 64 			if stamp, ok := s.pendingChannels[channelCf]; ok && time.Since(stamp) < 5*time.Second {
 65 				ev.Requested = true
 66@@ -1526,25 +1537,21 @@ func (s *Session) handleMessageRegistered(msg Message, playback bool) (Event, er
 67 		if err := msg.ParseParams(&target, &key, nil, &value); err != nil {
 68 			return nil, err
 69 		}
 70-		channelCf := s.Casemap(target)
 71-		c, ok := s.channels[channelCf]
 72-		if !ok {
 73-			return nil, nil
 74-		}
 75+		targetCf := s.Casemap(target)
 76+		m := s.metadata[targetCf]
 77 		switch key {
 78 		case "soju.im/pinned":
 79-			c.Pinned = value == "1"
 80+			m.Pinned = value == "1"
 81 		case "soju.im/muted":
 82-			c.Muted = value == "1"
 83-		}
 84-		s.channels[channelCf] = c
 85-		if c.complete {
 86-			return MetadataChangeEvent{
 87-				Target: target,
 88-				Pinned: c.Pinned,
 89-				Muted:  c.Muted,
 90-			}, nil
 91+			m.Muted = value == "1"
 92+		}
 93+		s.metadata[targetCf] = m
 94+		ev := MetadataChangeEvent{
 95+			Target: target,
 96+			Pinned: m.Pinned,
 97+			Muted:  m.Muted,
 98 		}
 99+		return ev, nil
100 	case "BOUNCER":
101 		if len(msg.Params) < 3 {
102 			break
+8, -4
 1@@ -607,13 +607,15 @@ func (bs *BufferList) GetPinned(netID, title string) bool {
 2 	return b.pinned
 3 }
 4 
 5-func (bs *BufferList) SetPinned(netID, title string, pinned bool) {
 6+func (bs *BufferList) SetPinned(netID, title string, pinned bool) int {
 7 	_, b := bs.at(netID, title)
 8 	if b == nil {
 9-		return
10+		return -1
11 	}
12 	b.pinned = pinned
13 	bs.reorder()
14+	i, _ := bs.at(netID, title)
15+	return i
16 }
17 
18 func (bs *BufferList) GetMuted(netID, title string) bool {
19@@ -624,13 +626,15 @@ func (bs *BufferList) GetMuted(netID, title string) bool {
20 	return b.muted
21 }
22 
23-func (bs *BufferList) SetMuted(netID, title string, muted bool) {
24+func (bs *BufferList) SetMuted(netID, title string, muted bool) int {
25 	_, b := bs.at(netID, title)
26 	if b == nil {
27-		return
28+		return -1
29 	}
30 	b.muted = muted
31 	bs.reorder()
32+	i, _ := bs.at(netID, title)
33+	return i
34 }
35 
36 func (bs *BufferList) clearRead(i int) {
+4, -4
 1@@ -554,16 +554,16 @@ func (ui *UI) GetPinned(netID, buffer string) bool {
 2 	return ui.bs.GetPinned(netID, buffer)
 3 }
 4 
 5-func (ui *UI) SetPinned(netID, buffer string, pinned bool) {
 6-	ui.bs.SetPinned(netID, buffer, pinned)
 7+func (ui *UI) SetPinned(netID, buffer string, pinned bool) int {
 8+	return ui.bs.SetPinned(netID, buffer, pinned)
 9 }
10 
11 func (ui *UI) GetMuted(netID, buffer string) bool {
12 	return ui.bs.GetMuted(netID, buffer)
13 }
14 
15-func (ui *UI) SetMuted(netID, buffer string, muted bool) {
16-	ui.bs.SetMuted(netID, buffer, muted)
17+func (ui *UI) SetMuted(netID, buffer string, muted bool) int {
18+	return ui.bs.SetMuted(netID, buffer, muted)
19 }
20 
21 func (ui *UI) SetRead(netID, buffer string, timestamp time.Time) {