diff options
author | Robin Jarry <robin@jarry.cc> | 2024-06-10 12:57:36 +0200 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2024-06-25 15:28:11 +0200 |
commit | 4e920d1def515f2c6d7da5168e39fd89fb200f63 (patch) | |
tree | 0eb1ff1a5827d5035246561479f0c233e24de32d /lib | |
parent | 7f66297c521fca8f9bc17280f0a96874598bde96 (diff) | |
download | aerc-4e920d1def515f2c6d7da5168e39fd89fb200f63.tar.gz |
threadbuilder: allow threading by subject
If no match were found in the References and In-Reply-To headers,
allow threading by looking at subjects.
This behaviour is disabled by default. Add a setting to enable it.
Changelog-added: Allow fallback to threading by subject with
`[ui].threading-by-subject`.
Signed-off-by: Robin Jarry <robin@jarry.cc>
Tested-by: Matěj Cepl <mcepl@cepl.eu>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/msgstore.go | 12 | ||||
-rw-r--r-- | lib/threadbuilder.go | 26 |
2 files changed, 28 insertions, 10 deletions
diff --git a/lib/msgstore.go b/lib/msgstore.go index b4790735..45b9cfd7 100644 --- a/lib/msgstore.go +++ b/lib/msgstore.go @@ -51,6 +51,7 @@ type MessageStore struct { selectLast bool reverseThreadOrder bool threadContext bool + threadBySubject bool sortThreadSiblings bool buildThreads bool builder *ThreadBuilder @@ -90,7 +91,7 @@ const MagicUid = 0xFFFFFFFF func NewMessageStore(worker *types.Worker, defaultSortCriteria []*types.SortCriterion, thread bool, clientThreads bool, clientThreadsDelay time.Duration, - selectLast bool, + selectLast bool, threadBySubject bool, reverseOrder bool, reverseThreadOrder bool, sortThreadSiblings bool, triggerNewEmail func(*models.MessageInfo), triggerDirectoryChange func(), triggerMailDeleted func(), @@ -118,6 +119,7 @@ func NewMessageStore(worker *types.Worker, threadedView: thread, buildThreads: clientThreads, threadContext: threadContext, + threadBySubject: threadBySubject, selectLast: selectLast, reverseThreadOrder: reverseThreadOrder, sortThreadSiblings: sortThreadSiblings, @@ -280,7 +282,7 @@ func (store *MessageStore) Update(msg types.WorkerMessage) { } case *types.DirectoryThreaded: if store.builder == nil { - store.builder = NewThreadBuilder(store.iterFactory) + store.builder = NewThreadBuilder(store.iterFactory, store.threadBySubject) } store.builder.RebuildUids(msg.Threads, store.reverseThreadOrder) store.uids = store.builder.Uids() @@ -424,7 +426,7 @@ func (store *MessageStore) update(threads bool) { store.runThreadBuilder() default: if store.builder == nil { - store.builder = NewThreadBuilder(store.iterFactory) + store.builder = NewThreadBuilder(store.iterFactory, store.threadBySubject) } store.threadsMutex.Lock() store.builder.RebuildUids(store.threads, store.reverseThreadOrder) @@ -478,7 +480,7 @@ func (store *MessageStore) BuildThreads() bool { func (store *MessageStore) runThreadBuilder() { if store.builder == nil { - store.builder = NewThreadBuilder(store.iterFactory) + store.builder = NewThreadBuilder(store.iterFactory, store.threadBySubject) for _, msg := range store.Messages { store.builder.Update(msg) } @@ -495,7 +497,7 @@ func (store *MessageStore) runThreadBuilder() { // runThreadBuilderNow runs the threadbuilder without any debounce logic func (store *MessageStore) runThreadBuilderNow() { if store.builder == nil { - store.builder = NewThreadBuilder(store.iterFactory) + store.builder = NewThreadBuilder(store.iterFactory, store.threadBySubject) for _, msg := range store.Messages { store.builder.Update(msg) } diff --git a/lib/threadbuilder.go b/lib/threadbuilder.go index b7dae431..abfbadb7 100644 --- a/lib/threadbuilder.go +++ b/lib/threadbuilder.go @@ -9,6 +9,7 @@ import ( "git.sr.ht/~rjarry/aerc/lib/log" "git.sr.ht/~rjarry/aerc/models" "git.sr.ht/~rjarry/aerc/worker/types" + sortthread "github.com/emersion/go-imap-sortthread" "github.com/gatherstars-com/jwz" ) @@ -18,13 +19,15 @@ type ThreadBuilder struct { threadedUids []uint32 threadMap map[uint32]*types.Thread iterFactory iterator.Factory + bySubject bool } -func NewThreadBuilder(i iterator.Factory) *ThreadBuilder { +func NewThreadBuilder(i iterator.Factory, bySubject bool) *ThreadBuilder { tb := &ThreadBuilder{ threadBlocks: make(map[uint32]jwz.Threadable), iterFactory: i, threadMap: make(map[uint32]*types.Thread), + bySubject: bySubject, } return tb } @@ -57,7 +60,8 @@ func (builder *ThreadBuilder) Update(msg *models.MessageInfo) { defer builder.Unlock() if msg != nil { - if threadable := newThreadable(msg); threadable != nil { + threadable := newThreadable(msg, builder.bySubject) + if threadable != nil { builder.threadBlocks[msg.Uid] = threadable } } @@ -244,9 +248,10 @@ type threadable struct { Parent jwz.Threadable Child jwz.Threadable Dummy bool + bySubject bool } -func newThreadable(msg *models.MessageInfo) *threadable { +func newThreadable(msg *models.MessageInfo, bySubject bool) *threadable { msgid, err := msg.MsgId() if err != nil { return nil @@ -258,6 +263,7 @@ func newThreadable(msg *models.MessageInfo) *threadable { Parent: nil, Child: nil, Dummy: false, + bySubject: bySubject, } } @@ -312,15 +318,25 @@ func (t *threadable) UID() uint32 { } func (t *threadable) Subject() string { - // deactivate threading by subject for now - return "" + if !t.bySubject || t.MsgInfo == nil || t.MsgInfo.Envelope == nil { + return "" + } + return t.MsgInfo.Envelope.Subject } func (t *threadable) SimplifiedSubject() string { + if t.bySubject { + subject, _ := sortthread.GetBaseSubject(t.Subject()) + return subject + } return "" } func (t *threadable) SubjectIsReply() bool { + if t.bySubject { + _, replyOrForward := sortthread.GetBaseSubject(t.Subject()) + return replyOrForward + } return false } |