commit fa4af97

gildarts  ·  2026-05-27 15:32:33 +0000 UTC
parent 9b2d6b5
Add nick-prefix option to show membership on messages

The option is off by default; enable with "nick-prefix true" in the
config. Adds Session.Membership(channel, nick) so callers can look up
a single user's membership without walking the full member list.

Fixes: #88
4 files changed,  +52, -0
M app.go
M app.go
+16, -0
 1@@ -2056,6 +2056,13 @@ func (app *App) formatMessage(s *irc.Session, ev irc.MessageEvent) (buffer strin
 2 		notification = ui.NotifyUnread
 3 	}
 4 
 5+	var membershipPrefix string
 6+	if app.cfg.NickPrefix && ev.TargetIsChannel {
 7+		if m := s.Membership(ev.Target, ev.User); m != "" {
 8+			membershipPrefix = m[:1]
 9+		}
10+	}
11+
12 	var head ui.StyledStringBuilder
13 	if ev.TargetPrefix != "" {
14 		head.WriteStyledString(ui.ColorString(ev.TargetPrefix, ui.ColorGreen))
15@@ -2069,12 +2076,18 @@ func (app *App) formatMessage(s *irc.Session, ev irc.MessageEvent) (buffer strin
16 		if head.Len() > 0 {
17 			head.WriteStyledString(ui.PlainString(" "))
18 		}
19+		if membershipPrefix != "" {
20+			head.WriteStyledString(ui.ColorString(membershipPrefix, ui.ColorGreen))
21+		}
22 		c := app.win.IdentColor(app.cfg.Colors.Nicks, ev.User, isFromSelf)
23 		head.WriteStyledString(ui.ColorString(ev.User, c))
24 	}
25 
26 	var body ui.StyledStringBuilder
27 	if isNotice {
28+		if membershipPrefix != "" {
29+			body.WriteStyledString(ui.ColorString(membershipPrefix, ui.ColorGreen))
30+		}
31 		color := app.win.IdentColor(app.cfg.Colors.Nicks, ev.User, isFromSelf)
32 		body.SetStyle(vaxis.Style{
33 			Foreground: color,
34@@ -2084,6 +2097,9 @@ func (app *App) formatMessage(s *irc.Session, ev irc.MessageEvent) (buffer strin
35 		body.WriteString(": ")
36 		body.WriteStyledString(ui.IRCString(content))
37 	} else if isAction {
38+		if membershipPrefix != "" {
39+			body.WriteStyledString(ui.ColorString(membershipPrefix, ui.ColorGreen))
40+		}
41 		color := app.win.IdentColor(app.cfg.Colors.Nicks, ev.User, isFromSelf)
42 		body.SetStyle(vaxis.Style{
43 			Foreground: color,
+10, -0
 1@@ -101,6 +101,7 @@ type Config struct {
 2 	ShowTypings bool
 3 	Typings     bool
 4 	Mouse       bool
 5+	NickPrefix  bool
 6 
 7 	Highlights       []string
 8 	OnHighlightPath  string
 9@@ -143,6 +144,7 @@ func Defaults() Config {
10 		TLSSkipVerify:    false,
11 		Channels:         nil,
12 		ShowTypings:      true,
13+		NickPrefix:       true,
14 		Typings:          true,
15 		Mouse:            true,
16 		Highlights:       nil,
17@@ -395,6 +397,14 @@ func unmarshal(filename string, cfg *Config) (err error) {
18 			if cfg.Mouse, err = strconv.ParseBool(mouse); err != nil {
19 				return err
20 			}
21+		case "nick-prefix":
22+			var nickPrefix string
23+			if err := d.ParseParams(&nickPrefix); err != nil {
24+				return err
25+			}
26+			if cfg.NickPrefix, err = strconv.ParseBool(nickPrefix); err != nil {
27+				return err
28+			}
29 		case "colors":
30 			for _, child := range d.Children {
31 				var colorStr string
+6, -0
 1@@ -126,6 +126,12 @@ pane-widths {
 2 *mouse*
 3 	Enable or disable mouse support.  Defaults to true.
 4 
 5+*nick-prefix*
 6+	Show the speaker's channel-membership prefix (e.g. *@* for an operator,
 7+	*+* for a voiced user) next to their nick on each message in a channel
 8+	buffer. Only the highest-priority prefix is shown. Has no effect in
 9+	private query buffers. Defaults to false.
10+
11 *colors* { ... }
12 	Settings for colors of different UI elements.
13 
+20, -0
 1@@ -310,6 +310,26 @@ func (s *Session) Casemap(name string) string {
 2 	return s.casemap(name)
 3 }
 4 
 5+// Membership returns the prefix-symbol string for nick's membership in the
 6+// given channel (e.g. "@", "+", "@+"), or "" if the target is not a known
 7+// channel or the nick is not a member. The string is ordered highest-priority
 8+// first, so callers wanting the single highest symbol can take string[:1].
 9+func (s *Session) Membership(channel, nick string) string {
10+	c, ok := s.channels[s.Casemap(channel)]
11+	if !ok {
12+		return ""
13+	}
14+	u, ok := s.users[s.Casemap(nick)]
15+	if !ok {
16+		return ""
17+	}
18+	m, ok := c.Members[u]
19+	if !ok {
20+		return ""
21+	}
22+	return m.Membership
23+}
24+
25 // Users returns the list of all known nicknames.
26 func (s *Session) Users() []string {
27 	users := make([]string, 0, len(s.users))