msgstore: run threadBuilder with no debounce on DirectoryContents msg

Commit 54a0a377e0 ("threads: debounce client-side thread building")
introduced the option to debounce threadbuilding to improve performance
of client side threads. This caused a UI regression during filtering of
mailboxes:

1. The mailbox contains the full set of message UIDs
2. User filters mailbox
3. A DirectoryContents message is received from worker with the proper
   UIDs to display
4. Debounce is started (in a separate go routine)
5. The value of msgStore.Uids() is used to show pending headers, but is
   not updated until the threadbuilder runs. The full set of UIDs is
   shown briefly
6. Debounce is over, threadbuilder runs, updates msgStore.Uids(), proper
   messages show.

Run the thread builder immediately upon receipt of a DirectoryContents
message, bypassing any debounce. Performance will remain the same: the
debounce is meant to prevent multiple sequential calls to the thread
builder during scrolling. This is unlikely to occur in rapid succession
from filtering or sorting.

Fixes: https://todo.sr.ht/~rjarry/aerc/76
Fixes: 54a0a377e0 ("threads: debounce client-side thread building")
Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
Tim Culverhouse 2022-08-30 10:36:40 -05:00 committed by Robin Jarry
parent 921382a9bf
commit 380cf13cff

View file

@ -208,7 +208,7 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
} }
store.Messages = newMap store.Messages = newMap
store.uids = msg.Uids store.uids = msg.Uids
update = true store.runThreadBuilderNow()
case *types.DirectoryThreaded: case *types.DirectoryThreaded:
var uids []uint32 var uids []uint32
newMap := make(map[uint32]*models.MessageInfo) newMap := make(map[uint32]*models.MessageInfo)
@ -368,37 +368,42 @@ func (store *MessageStore) BuildThreads() bool {
} }
func (store *MessageStore) runThreadBuilder() { func (store *MessageStore) runThreadBuilder() {
if store.builder == nil {
store.builder = NewThreadBuilder()
for _, msg := range store.Messages {
store.builder.Update(msg)
}
}
if store.threadBuilderDebounce != nil { if store.threadBuilderDebounce != nil {
if store.threadBuilderDebounce.Stop() { if store.threadBuilderDebounce.Stop() {
logging.Infof("thread builder debounced") logging.Infof("thread builder debounced")
} }
} }
store.threadBuilderDebounce = time.AfterFunc(store.threadBuilderDelay, func() { store.threadBuilderDebounce = time.AfterFunc(store.threadBuilderDelay, func() {
// build new threads store.runThreadBuilderNow()
th := store.builder.Threads(store.uids)
// save local threads to the message store variable and
// run callback if defined (callback should reposition cursor)
store.threadsMutex.Lock()
store.threads = th
if store.threadCallback != nil {
store.threadCallback()
}
store.threadsMutex.Unlock()
// invalidate message list
if store.onUpdate != nil {
store.onUpdate(store)
}
}) })
} }
// runThreadBuilderNow runs the threadbuilder without any debounce logic
func (store *MessageStore) runThreadBuilderNow() {
if store.builder == nil {
store.builder = NewThreadBuilder()
for _, msg := range store.Messages {
store.builder.Update(msg)
}
}
// build new threads
th := store.builder.Threads(store.uids)
// save local threads to the message store variable and
// run callback if defined (callback should reposition cursor)
store.threadsMutex.Lock()
store.threads = th
if store.threadCallback != nil {
store.threadCallback()
}
store.threadsMutex.Unlock()
// invalidate message list
if store.onUpdate != nil {
store.onUpdate(store)
}
}
// SelectedThread returns the thread with the UID from the selected message // SelectedThread returns the thread with the UID from the selected message
func (store *MessageStore) SelectedThread() *types.Thread { func (store *MessageStore) SelectedThread() *types.Thread {
var thread *types.Thread var thread *types.Thread