chat: Sort NamesPrefix by recently active origin/autocomplete-sort
authorAndrey Petrov <andrey.petrov@shazow.net>
Sat, 16 Mar 2019 19:27:43 +0000 (15:27 -0400)
committerAndrey Petrov <andrey.petrov@shazow.net>
Sun, 17 Mar 2019 18:41:03 +0000 (14:41 -0400)
chat/message/user.go
chat/room.go
chat/room_test.go

index d094bde6e8d53ca6d1d87aa744490d525288e173..43da001294799c551b0679de1d713b8a6362a2d1 100644 (file)
@@ -238,3 +238,16 @@ func init() {
 
        // TODO: Seed random?
 }
+
+// RecentActiveUsers is a slice of *Users that knows how to be sorted by the time of the last message.
+type RecentActiveUsers []*User
+
+func (a RecentActiveUsers) Len() int      { return len(a) }
+func (a RecentActiveUsers) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a RecentActiveUsers) Less(i, j int) bool {
+       a[i].mu.Lock()
+       defer a[i].mu.Unlock()
+       a[j].mu.Lock()
+       defer a[j].mu.Unlock()
+       return a[i].lastMsg.After(a[j].lastMsg)
+}
index 71e3171817d038c917f5a18a1a748f8782237b79..851d0e3d50d66a9a5c092b9b54eac1faa28eb36d 100644 (file)
@@ -4,6 +4,7 @@ import (
        "errors"
        "fmt"
        "io"
+       "sort"
        "sync"
 
        "github.com/shazow/ssh-chat/chat/message"
@@ -227,12 +228,21 @@ func (r *Room) SetTopic(s string) {
 }
 
 // NamesPrefix lists all members' names with a given prefix, used to query
-// for autocompletion purposes.
+// for autocompletion purposes. Sorted by which user was last active.
 func (r *Room) NamesPrefix(prefix string) []string {
        items := r.Members.ListPrefix(prefix)
-       names := make([]string, len(items))
-       for i, item := range items {
-               names[i] = item.Value().(*Member).User.Name()
+
+       // Sort results by recently active
+       users := make([]*message.User, 0, len(items))
+       for _, item := range items {
+               users = append(users, item.Value().(*Member).User)
+       }
+       sort.Sort(message.RecentActiveUsers(users))
+
+       // Pull out names
+       names := make([]string, 0, len(items))
+       for _, user := range users {
+               names = append(names, user.Name())
        }
        return names
 }
index e30c170a1db17ea16176377aca408099b08d23e7..77c77f71c3aeb9f4d98146931368ac2fe00f5581 100644 (file)
@@ -8,6 +8,7 @@ import (
        "time"
 
        "github.com/shazow/ssh-chat/chat/message"
+       "github.com/shazow/ssh-chat/set"
 )
 
 // Used for testing
@@ -362,3 +363,44 @@ func TestRoomNames(t *testing.T) {
                t.Errorf("Got: %q; Expected: %q", actual, expected)
        }
 }
+
+func TestRoomNamesPrefix(t *testing.T) {
+       r := NewRoom()
+
+       s := &MockScreen{}
+       members := []*Member{
+               &Member{User: message.NewUserScreen(message.SimpleID("aaa"), s)},
+               &Member{User: message.NewUserScreen(message.SimpleID("aab"), s)},
+               &Member{User: message.NewUserScreen(message.SimpleID("aac"), s)},
+               &Member{User: message.NewUserScreen(message.SimpleID("foo"), s)},
+       }
+
+       for _, m := range members {
+               if err := r.Members.Add(set.Itemize(m.ID(), m)); err != nil {
+                       t.Fatal(err)
+               }
+       }
+
+       // Inject some activity
+       members[2].HandleMsg(message.NewMsg("hi")) // aac
+       members[0].HandleMsg(message.NewMsg("hi")) // aaa
+       members[3].HandleMsg(message.NewMsg("hi")) // foo
+       members[1].HandleMsg(message.NewMsg("hi")) // aab
+
+       if got, want := r.NamesPrefix("a"), []string{"aab", "aaa", "aac"}; !reflect.DeepEqual(got, want) {
+               t.Errorf("got: %q; want: %q", got, want)
+       }
+
+       members[2].HandleMsg(message.NewMsg("hi")) // aac
+       if got, want := r.NamesPrefix("a"), []string{"aac", "aab", "aaa"}; !reflect.DeepEqual(got, want) {
+               t.Errorf("got: %q; want: %q", got, want)
+       }
+
+       if got, want := r.NamesPrefix("f"), []string{"foo"}; !reflect.DeepEqual(got, want) {
+               t.Errorf("got: %q; want: %q", got, want)
+       }
+
+       if got, want := r.NamesPrefix("bar"), []string{}; !reflect.DeepEqual(got, want) {
+               t.Errorf("got: %q; want: %q", got, want)
+       }
+}