aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/msgstore.go48
-rw-r--r--lib/threadbuilder.go59
-rw-r--r--worker/types/thread.go13
3 files changed, 70 insertions, 50 deletions
diff --git a/lib/msgstore.go b/lib/msgstore.go
index 369f4b45..bd9e935b 100644
--- a/lib/msgstore.go
+++ b/lib/msgstore.go
@@ -2,7 +2,6 @@ package lib
import (
"io"
- gosort "sort"
"time"
"git.sr.ht/~rjarry/aerc/lib/sort"
@@ -339,8 +338,6 @@ func (store *MessageStore) SetBuildThreads(buildThreads bool) {
store.buildThreads = buildThreads
if store.BuildThreads() {
store.runThreadBuilder()
- } else {
- store.rebuildUids()
}
}
@@ -354,46 +351,18 @@ func (store *MessageStore) BuildThreads() bool {
func (store *MessageStore) runThreadBuilder() {
if store.builder == nil {
- store.builder = NewThreadBuilder(store, store.worker.Logger)
+ store.builder = NewThreadBuilder(store.worker.Logger)
for _, msg := range store.Messages {
store.builder.Update(msg)
}
}
- store.Threads = store.builder.Threads()
- store.rebuildUids()
-}
-
-func (store *MessageStore) rebuildUids() {
- start := time.Now()
-
- uids := make([]uint32, 0, len(store.Uids()))
-
- if store.BuildThreads() {
- gosort.Sort(types.ByUID(store.Threads))
- for i := len(store.Threads) - 1; i >= 0; i-- {
- store.Threads[i].Walk(func(t *types.Thread, level int, currentErr error) error {
- uids = append(uids, t.Uid)
- return nil
- })
- }
- uidsReversed := make([]uint32, len(uids))
- for i := 0; i < len(uids); i++ {
- uidsReversed[i] = uids[len(uids)-1-i]
- }
- uids = uidsReversed
- } else {
- uids = store.Uids()
- gosort.SliceStable(uids, func(i, j int) bool { return uids[i] < uids[j] })
- }
-
+ var uids []uint32
if store.filter {
- store.results = uids
+ uids = store.results
} else {
- store.uids = uids
+ uids = store.uids
}
-
- elapsed := time.Since(start)
- store.worker.Logger.Println("Store: Rebuilding UIDs took", elapsed)
+ store.Threads = store.builder.Threads(uids)
}
func (store *MessageStore) Delete(uids []uint32,
@@ -472,6 +441,13 @@ func (store *MessageStore) Answered(uids []uint32, answered bool,
}
func (store *MessageStore) Uids() []uint32 {
+
+ if store.BuildThreads() && store.builder != nil {
+ if uids := store.builder.Uids(); len(uids) > 0 {
+ return uids
+ }
+ }
+
if store.filter {
return store.results
}
diff --git a/lib/threadbuilder.go b/lib/threadbuilder.go
index c87d0bfb..9607f1cc 100644
--- a/lib/threadbuilder.go
+++ b/lib/threadbuilder.go
@@ -9,29 +9,33 @@ import (
"github.com/gatherstars-com/jwz"
)
-type UidStorer interface {
- Uids() []uint32
-}
-
type ThreadBuilder struct {
threadBlocks map[uint32]jwz.Threadable
messageidToUid map[string]uint32
seen map[uint32]bool
- store UidStorer
+ threadedUids []uint32
logger *log.Logger
}
-func NewThreadBuilder(store UidStorer, logger *log.Logger) *ThreadBuilder {
+func NewThreadBuilder(logger *log.Logger) *ThreadBuilder {
tb := &ThreadBuilder{
threadBlocks: make(map[uint32]jwz.Threadable),
messageidToUid: make(map[string]uint32),
seen: make(map[uint32]bool),
- store: store,
logger: logger,
}
return tb
}
+// Uids returns the uids in threading order
+func (builder *ThreadBuilder) Uids() []uint32 {
+ if builder.threadedUids == nil {
+ return []uint32{}
+ }
+ return builder.threadedUids
+}
+
+// Update updates the thread builder with a new message header
func (builder *ThreadBuilder) Update(msg *models.MessageInfo) {
if msg != nil {
if threadable := newThreadable(msg); threadable != nil {
@@ -41,10 +45,17 @@ func (builder *ThreadBuilder) Update(msg *models.MessageInfo) {
}
}
-func (builder *ThreadBuilder) Threads() []*types.Thread {
+// Threads returns a slice of threads for the given list of uids
+func (builder *ThreadBuilder) Threads(uids []uint32) []*types.Thread {
start := time.Now()
- threads := builder.buildAercThreads(builder.generateStructure())
+ threads := builder.buildAercThreads(builder.generateStructure(uids), uids)
+
+ // sort threads according to uid ordering
+ builder.sortThreads(threads, uids)
+
+ // rebuild uids from threads
+ builder.RebuildUids(threads)
elapsed := time.Since(start)
builder.logger.Println("ThreadBuilder:", len(threads), "threads created in", elapsed)
@@ -52,9 +63,9 @@ func (builder *ThreadBuilder) Threads() []*types.Thread {
return threads
}
-func (builder *ThreadBuilder) generateStructure() jwz.Threadable {
+func (builder *ThreadBuilder) generateStructure(uids []uint32) jwz.Threadable {
jwzThreads := make([]jwz.Threadable, 0, len(builder.threadBlocks))
- for _, uid := range builder.store.Uids() {
+ for _, uid := range uids {
if thr, ok := builder.threadBlocks[uid]; ok {
jwzThreads = append(jwzThreads, thr)
}
@@ -68,15 +79,15 @@ func (builder *ThreadBuilder) generateStructure() jwz.Threadable {
return threadStructure
}
-func (builder *ThreadBuilder) buildAercThreads(structure jwz.Threadable) []*types.Thread {
+func (builder *ThreadBuilder) buildAercThreads(structure jwz.Threadable, uids []uint32) []*types.Thread {
threads := make([]*types.Thread, 0, len(builder.threadBlocks))
if structure == nil {
- for _, uid := range builder.store.Uids() {
+ for _, uid := range uids {
threads = append(threads, &types.Thread{Uid: uid})
}
} else {
// fill threads with nil messages
- for _, uid := range builder.store.Uids() {
+ for _, uid := range uids {
if _, ok := builder.threadBlocks[uid]; !ok {
threads = append(threads, &types.Thread{Uid: uid})
}
@@ -127,6 +138,26 @@ func (builder *ThreadBuilder) buildTree(treeNode jwz.Threadable, target *types.T
}
}
+func (builder *ThreadBuilder) sortThreads(threads []*types.Thread, orderedUids []uint32) {
+ types.SortThreadsBy(threads, orderedUids)
+}
+
+// RebuildUids rebuilds the uids from the given slice of threads
+func (builder *ThreadBuilder) RebuildUids(threads []*types.Thread) {
+ uids := make([]uint32, 0, len(threads))
+ for i := len(threads) - 1; i >= 0; i-- {
+ threads[i].Walk(func(t *types.Thread, level int, currentErr error) error {
+ uids = append(uids, t.Uid)
+ return nil
+ })
+ }
+ // copy in reverse as msgList displays backwards
+ for i, j := 0, len(uids)-1; i < j; i, j = i+1, j-1 {
+ uids[i], uids[j] = uids[j], uids[i]
+ }
+ builder.threadedUids = uids
+}
+
// threadable implements the jwz.threadable interface which is required for the
// jwz threading algorithm
type threadable struct {
diff --git a/worker/types/thread.go b/worker/types/thread.go
index 48e4a002..7c0cc5b8 100644
--- a/worker/types/thread.go
+++ b/worker/types/thread.go
@@ -3,6 +3,7 @@ package types
import (
"errors"
"fmt"
+ "sort"
)
type Thread struct {
@@ -120,3 +121,15 @@ func (s ByUID) Less(i, j int) bool {
maxUID_j := getMaxUID(s[j])
return maxUID_i < maxUID_j
}
+
+func SortThreadsBy(toSort []*Thread, sortBy []uint32) {
+ // build a map from sortBy
+ uidMap := make(map[uint32]int)
+ for i, uid := range sortBy {
+ uidMap[uid] = i
+ }
+ // sortslice of toSort with less function of indexing the map sortBy
+ sort.Slice(toSort, func(i, j int) bool {
+ return uidMap[getMaxUID(toSort[i])] < uidMap[getMaxUID(toSort[j])]
+ })
+}