~delthas/senpai-dev

Enable recent-priority tab completion v1 PROPOSED

Angus Gibson: 1
 Enable recent-priority tab completion

 5 files changed, 34 insertions(+), 15 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.sr.ht/~delthas/senpai-dev/patches/55413/mbox | git am -3
Learn more about email & git

[PATCH v1] Enable recent-priority tab completion Export this patch

An attempt to address https://todo.sr.ht/~delthas/senpai/139. A
session can now return the names for a given target in order of
recency (but still preferring higher modes -- maybe this should be
changed).
---
 app.go         |  4 ++--
 commands.go    |  2 +-
 completions.go |  2 +-
 irc/session.go | 35 +++++++++++++++++++++++++----------
 irc/tokens.go  |  6 +++++-
 5 files changed, 34 insertions(+), 15 deletions(-)

diff --git a/app.go b/app.go
index 3425d66..4db0f00 100644
--- a/app.go
+++ b/app.go
@@ -301,7 +301,7 @@ func (app *App) eventLoop() {
			netID, buffer := app.win.CurrentBuffer()
			s := app.sessions[netID]
			if s != nil && buffer != "" {
				currentMembers = s.Names(buffer)
				currentMembers = s.Names(buffer, false)
			}
			app.win.Draw(currentMembers)
			var title strings.Builder
@@ -705,7 +705,7 @@ func (app *App) handleMouseEvent(ev vaxis.Mouse) {
				} else {
					s := app.sessions[netID]
					if s != nil && target != "" {
						members := s.Names(target)
						members := s.Names(target, false)
						if i < len(members) {
							buffer := members[i].Name.Name
							i, added := app.win.AddBuffer(netID, "", buffer)
diff --git a/commands.go b/commands.go
index 6ef0ddb..c3fe257 100644
--- a/commands.go
+++ b/commands.go
@@ -540,7 +540,7 @@ func commandDoNames(app *App, args []string) (err error) {
		Foreground: app.cfg.Colors.Status,
	})
	sb.WriteString("Names: ")
	for _, name := range s.Names(buffer) {
	for _, name := range s.Names(buffer, false) {
		if name.PowerLevel != "" {
			sb.SetStyle(vaxis.Style{
				Foreground: vaxis.IndexColor(2),
diff --git a/completions.go b/completions.go
index e641c14..079c266 100644
--- a/completions.go
+++ b/completions.go
@@ -27,7 +27,7 @@ func (app *App) completionsChannelMembers(cs []ui.Completion, cursorIdx int, tex
	netID, buffer := app.win.CurrentBuffer()
	s := app.sessions[netID] // is not nil
	wordCf := s.Casemap(string(word))
	for _, name := range s.Names(buffer) {
	for _, name := range s.Names(buffer, true) {
		if strings.HasPrefix(s.Casemap(name.Name.Name), wordCf) {
			nickComp := []rune(name.Name.Name)
			if start == 0 {
diff --git a/irc/session.go b/irc/session.go
index d05a20a..c0659bd 100644
--- a/irc/session.go
+++ b/irc/session.go
@@ -91,12 +91,13 @@ type User struct {

// Channel is a joined channel.
type Channel struct {
	Name      string           // the name of the channel.
	Members   map[*User]string // the set of members associated with their membership.
	Topic     string           // the topic of the channel, or "" if absent.
	TopicWho  *Prefix          // the name of the last user who set the topic.
	TopicTime time.Time        // the last time the topic has been changed.
	Read      time.Time        // the time until which messages were read.
	Name       string              // the name of the channel.
	Members    map[*User]string    // the set of members associated with their membership.
	LastActive map[*User]time.Time // when a member last sent a message to the channel.
	Topic      string              // the topic of the channel, or "" if absent.
	TopicWho   *Prefix             // the name of the last user who set the topic.
	TopicTime  time.Time           // the last time the topic has been changed.
	Read       time.Time           // the time until which messages were read.

	complete bool // whether this structure is fully initialized.
}
@@ -294,18 +295,23 @@ func (s *Session) Users() []string {
// Names returns the list of users in the given target, or nil if the target
// is not a known channel or nick in the session.
// The list is sorted according to member name.
func (s *Session) Names(target string) []Member {
func (s *Session) Names(target string, recent bool) []Member {
	var names []Member
	if s.IsChannel(target) {
		if c, ok := s.channels[s.Casemap(target)]; ok {
			names = make([]Member, 0, len(c.Members))
			for u, pl := range c.Members {
				var lastActive time.Time
				if t, ok := c.LastActive[u]; ok {
					lastActive = t
				}
				names = append(names, Member{
					PowerLevel:   pl,
					Name:         u.Name.Copy(),
					Away:         u.Away,
					Disconnected: u.Disconnected,
					Self:         s.nickCf == s.casemap(u.Name.Name),
					LastActive:   lastActive,
				})
			}
		}
@@ -914,8 +920,9 @@ func (s *Session) handleMessageRegistered(msg Message, playback bool) (Event, er

		if s.IsMe(nickCf) {
			s.channels[channelCf] = Channel{
				Name:    msg.Params[0],
				Members: map[*User]string{},
				Name:       msg.Params[0],
				Members:    map[*User]string{},
				LastActive: map[*User]time.Time{},
			}
			if _, ok := s.enabledCaps["away-notify"]; ok {
				// Only try to know who is away if the list is
@@ -1979,12 +1986,14 @@ func (s *Session) newMessageEvent(msg Message) (ev MessageEvent, err error) {
		return ev, err
	}

	msgTime := msg.TimeOrNow()

	ev = MessageEvent{
		User:    msg.Prefix.Name, // TODO correctly casemap
		Target:  target,          // TODO correctly casemap
		Command: msg.Command,
		Content: content,
		Time:    msg.TimeOrNow(),
		Time:    msgTime,
	}

	if s.IsMe(target) {
@@ -1993,9 +2002,15 @@ func (s *Session) newMessageEvent(msg Message) (ev MessageEvent, err error) {
		}
	}
	targetCf := s.Casemap(target)
	nameCf := s.Casemap(msg.Prefix.Name)
	if c, ok := s.channels[targetCf]; ok {
		ev.Target = c.Name
		ev.TargetIsChannel = true
		if u, ok := s.users[nameCf]; ok {
			if msgTime.After(c.LastActive[u]) {
				c.LastActive[u] = msgTime
			}
		}
	}

	return ev, nil
diff --git a/irc/tokens.go b/irc/tokens.go
index db94ae4..ea4c36c 100644
--- a/irc/tokens.go
+++ b/irc/tokens.go
@@ -467,6 +467,7 @@ type Member struct {
	Away         bool
	Disconnected bool
	Self         bool // Added by senpai
	LastActive   time.Time
}

type members struct {
@@ -493,7 +494,10 @@ func (m members) Less(i, j int) bool {
	if pi != pj {
		return pi < pj
	}
	return strings.ToLower(m.m[i].Name.Name) < strings.ToLower(m.m[j].Name.Name)
	if m.m[i].LastActive.IsZero() && m.m[j].LastActive.IsZero() {
		return strings.ToLower(m.m[i].Name.Name) < strings.ToLower(m.m[j].Name.Name)
	}
	return m.m[i].LastActive.After(m.m[j].LastActive)
}

func (m members) Swap(i, j int) {

base-commit: 18998b07376644d4450d03107d04fb188fd6c5b9
-- 
2.46.2