aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authory0ast <joost@joo.st>2021-11-12 18:12:02 +0100
committerRobin Jarry <robin@jarry.cc>2021-11-13 15:05:59 +0100
commitdc2a2c2dfd6dc327fe40fbf2da922ef6c3d520be (patch)
tree4987160692aca01e27b068cb256d66d373556a52 /lib
parentc303b953360994966ff657c4e17670853198ecf7 (diff)
downloadaerc-dc2a2c2dfd6dc327fe40fbf2da922ef6c3d520be.tar.gz
messages: allow displaying email threads
Display threads in the message list. For now, only supported by the notmuch backend and on IMAP when the server supports the THREAD extension. Setting threading-enable=true is global and will cause the message list to be empty with maildir:// accounts. Co-authored-by: Kevin Kuehler <keur@xcf.berkeley.edu> Co-authored-by: Reto Brunner <reto@labrat.space> Signed-off-by: Robin Jarry <robin@jarry.cc>
Diffstat (limited to 'lib')
-rw-r--r--lib/format/format.go12
-rw-r--r--lib/msgstore.go55
2 files changed, 61 insertions, 6 deletions
diff --git a/lib/format/format.go b/lib/format/format.go
index 8681de8e..59b5c479 100644
--- a/lib/format/format.go
+++ b/lib/format/format.go
@@ -45,6 +45,10 @@ type Ctx struct {
MsgNum int
MsgInfo *models.MessageInfo
MsgIsMarked bool
+
+ // UI controls for threading
+ ThreadPrefix string
+ ThreadSameSubject bool
}
func ParseMessageFormat(format string, timeFmt string, thisDayTimeFmt string,
@@ -213,7 +217,13 @@ func ParseMessageFormat(format string, timeFmt string, thisDayTimeFmt string,
args = append(args, addrs)
case 's':
retval = append(retval, 's')
- args = append(args, envelope.Subject)
+ // if we are threaded strip the repeated subjects unless it's the
+ // first on the screen
+ subject := envelope.Subject
+ if ctx.ThreadSameSubject {
+ subject = ""
+ }
+ args = append(args, ctx.ThreadPrefix+subject)
case 't':
if len(envelope.To) == 0 {
return "", nil,
diff --git a/lib/msgstore.go b/lib/msgstore.go
index b1faa738..40720b46 100644
--- a/lib/msgstore.go
+++ b/lib/msgstore.go
@@ -17,7 +17,8 @@ type MessageStore struct {
Sorting bool
// Ordered list of known UIDs
- uids []uint32
+ uids []uint32
+ Threads []*types.Thread
selected int
bodyCallbacks map[uint32][]func(*types.FullMessage)
@@ -35,6 +36,8 @@ type MessageStore struct {
defaultSortCriteria []*types.SortCriterion
+ thread bool
+
// Map of uids we've asked the worker to fetch
onUpdate func(store *MessageStore) // TODO: multiple onUpdate handlers
onUpdateDirs func()
@@ -52,6 +55,7 @@ type MessageStore struct {
func NewMessageStore(worker *types.Worker,
dirInfo *models.DirectoryInfo,
defaultSortCriteria []*types.SortCriterion,
+ thread bool,
triggerNewEmail func(*models.MessageInfo),
triggerDirectoryChange func()) *MessageStore {
@@ -67,6 +71,8 @@ func NewMessageStore(worker *types.Worker,
bodyCallbacks: make(map[uint32][]func(*types.FullMessage)),
headerCallbacks: make(map[uint32][]func(*types.MessageInfo)),
+ thread: thread,
+
defaultSortCriteria: defaultSortCriteria,
pendingBodies: make(map[uint32]interface{}),
@@ -189,6 +195,27 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
store.Messages = newMap
store.uids = msg.Uids
update = true
+ case *types.DirectoryThreaded:
+ var uids []uint32
+ newMap := make(map[uint32]*models.MessageInfo)
+
+ for i := len(msg.Threads) - 1; i >= 0; i-- {
+ msg.Threads[i].Walk(func(t *types.Thread, level int, currentErr error) error {
+ uid := t.Uid
+ uids = append([]uint32{uid}, uids...)
+ if msg, ok := store.Messages[uid]; ok {
+ newMap[uid] = msg
+ } else {
+ newMap[uid] = nil
+ directoryChange = true
+ }
+ return nil
+ })
+ }
+ store.Messages = newMap
+ store.uids = uids
+ store.Threads = msg.Threads
+ update = true
case *types.MessageInfo:
if existing, ok := store.Messages[msg.Info.Uid]; ok && existing != nil {
merge(existing, msg.Info)
@@ -257,6 +284,15 @@ func (store *MessageStore) Update(msg types.WorkerMessage) {
}
store.results = newResults
+ for _, thread := range store.Threads {
+ thread.Walk(func(t *types.Thread, _ int, _ error) error {
+ if _, deleted := toDelete[t.Uid]; deleted {
+ t.Deleted = true
+ }
+ return nil
+ })
+ }
+
update = true
}
@@ -592,14 +628,23 @@ func (store *MessageStore) ModifyLabels(uids []uint32, add, remove []string,
func (store *MessageStore) Sort(criteria []*types.SortCriterion, cb func()) {
store.Sorting = true
- store.worker.PostAction(&types.FetchDirectoryContents{
- SortCriteria: criteria,
- }, func(_ types.WorkerMessage) {
+
+ handle_return := func(msg types.WorkerMessage) {
store.Sorting = false
if cb != nil {
cb()
}
- })
+ }
+
+ if store.thread {
+ store.worker.PostAction(&types.FetchDirectoryThreaded{
+ SortCriteria: criteria,
+ }, handle_return)
+ } else {
+ store.worker.PostAction(&types.FetchDirectoryContents{
+ SortCriteria: criteria,
+ }, handle_return)
+ }
}
// returns the index of needle in haystack or -1 if not found