diff options
author | Koni Marti <koni.marti@gmail.com> | 2023-07-18 10:29:52 +0200 |
---|---|---|
committer | Robin Jarry <robin@jarry.cc> | 2024-06-25 15:28:11 +0200 |
commit | 7f66297c521fca8f9bc17280f0a96874598bde96 (patch) | |
tree | 643e1d5c6dbbf55814c689f2509f3eb9bd532fa2 | |
parent | 9cd806fa6e80829753ecd3356e19044d6e210826 (diff) | |
download | aerc-7f66297c521fca8f9bc17280f0a96874598bde96.tar.gz |
threadbuilder: show siblings even when no parent found
Show all threading associations even when not all nodes are present.
Indicate if a thread is incomplete, i.e. misses a direct parent node.
Use the `msglist_thread_orphan.fg=red` styleobject in your stylesheet to
indicate whether a messsage has a missing parent.
Also use a different thread prefix ("┬─" instead of "├─") not to confuse
them with regular threads that have a visible parent.
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Signed-off-by: Robin Jarry <robin@jarry.cc>
Tested-by: Matěj Cepl <mcepl@cepl.eu>
-rw-r--r-- | app/msglist.go | 30 | ||||
-rw-r--r-- | config/style.go | 2 | ||||
-rw-r--r-- | config/templates.go | 1 | ||||
-rw-r--r-- | doc/aerc-stylesets.7.scd | 3 | ||||
-rw-r--r-- | lib/state/templates.go | 18 | ||||
-rw-r--r-- | lib/threadbuilder.go | 36 | ||||
-rw-r--r-- | models/templates.go | 1 | ||||
-rw-r--r-- | worker/types/thread.go | 3 |
8 files changed, 62 insertions, 32 deletions
diff --git a/app/msglist.go b/app/msglist.go index 996ffa0c..24547b64 100644 --- a/app/msglist.go +++ b/app/msglist.go @@ -231,6 +231,9 @@ func addMessage( if templateData.ThreadContext() { params.styles = append(params.styles, config.STYLE_MSGLIST_THREAD_CONTEXT) } + if templateData.ThreadOrphan() { + params.styles = append(params.styles, config.STYLE_MSGLIST_THREAD_ORPHAN) + } } // marked message marked := store.Marker().IsMarked(msg.Uid) @@ -482,16 +485,20 @@ func threadPrefix(t *types.Thread, reverse bool, msglist bool) string { var hiddenOffspring bool = t.FirstChild != nil && t.FirstChild.Hidden > 0 var parentAndSiblings bool = t.Parent != nil && t.NextSibling != nil + var hasSiblings string = uiConfig.ThreadPrefixHasSiblings + if t.Parent != nil && t.Parent.Hidden > 0 && t.Hidden == 0 { + hasSiblings = dummy + } switch { case parentAndSiblings && hiddenOffspring: - prefix = uiConfig.ThreadPrefixHasSiblings + + prefix = hasSiblings + uiConfig.ThreadPrefixFolded case parentAndSiblings && t.FirstChild != nil: - prefix = uiConfig.ThreadPrefixHasSiblings + + prefix = hasSiblings + firstChild + tip case parentAndSiblings: - prefix = uiConfig.ThreadPrefixHasSiblings + + prefix = hasSiblings + uiConfig.ThreadPrefixLimb + uiConfig.ThreadPrefixUnfolded + tip case t.Parent != nil && hiddenOffspring: @@ -557,18 +564,19 @@ func newThreadView(store *lib.MessageStore) *threadView { } func (t *threadView) Update(data state.DataSetter, uid uint32) { - prefix, same, count, unread, folded, context := "", false, 0, 0, false, false thread, err := t.store.Thread(uid) + info := state.ThreadInfo{} if thread != nil && err == nil { - prefix = threadPrefix(thread, t.reverse, true) + info.Prefix = threadPrefix(thread, t.reverse, true) subject := threadSubject(t.store, thread) - same = subject == t.prevSubj && sameParent(thread, t.prev) && !isParent(thread) + info.SameSubject = subject == t.prevSubj && sameParent(thread, t.prev) && !isParent(thread) t.prev = thread t.prevSubj = subject - count = countThreads(thread) - unread = unreadInThread(thread, t.store) - folded = thread.FirstChild != nil && thread.FirstChild.Hidden != 0 - context = thread.Context + info.Count = countThreads(thread) + info.Unread = unreadInThread(thread, t.store) + info.Folded = thread.FirstChild != nil && thread.FirstChild.Hidden != 0 + info.Context = thread.Context + info.Orphan = thread.Parent != nil && thread.Parent.Hidden > 0 && thread.Hidden == 0 } - data.SetThreading(prefix, same, count, unread, folded, context) + data.SetThreading(info) } diff --git a/config/style.go b/config/style.go index 95e60616..46c46378 100644 --- a/config/style.go +++ b/config/style.go @@ -42,6 +42,7 @@ const ( STYLE_MSGLIST_GUTTER STYLE_MSGLIST_PILL STYLE_MSGLIST_THREAD_CONTEXT + STYLE_MSGLIST_THREAD_ORPHAN STYLE_DIRLIST_DEFAULT STYLE_DIRLIST_UNREAD @@ -92,6 +93,7 @@ var StyleNames = map[string]StyleObject{ "msglist_thread_folded": STYLE_MSGLIST_THREAD_FOLDED, "msglist_thread_context": STYLE_MSGLIST_THREAD_CONTEXT, + "msglist_thread_orphan": STYLE_MSGLIST_THREAD_ORPHAN, "dirlist_default": STYLE_DIRLIST_DEFAULT, "dirlist_unread": STYLE_DIRLIST_UNREAD, diff --git a/config/templates.go b/config/templates.go index 5a38cd61..4000b1fc 100644 --- a/config/templates.go +++ b/config/templates.go @@ -82,6 +82,7 @@ func (d *dummyData) ThreadCount() int { return 0 } func (d *dummyData) ThreadUnread() int { return 0 } func (d *dummyData) ThreadFolded() bool { return false } func (d *dummyData) ThreadContext() bool { return true } +func (d *dummyData) ThreadOrphan() bool { return true } func (d *dummyData) Subject() string { return "Re: [PATCH] hey" } func (d *dummyData) SubjectBase() string { return "[PATCH] hey" } func (d *dummyData) Attach(string) string { return "" } diff --git a/doc/aerc-stylesets.7.scd b/doc/aerc-stylesets.7.scd index bfe9dc05..d86d9f98 100644 --- a/doc/aerc-stylesets.7.scd +++ b/doc/aerc-stylesets.7.scd @@ -117,6 +117,8 @@ styling. : Visible messages that have folded thread children. | *msglist_thread_context* : The messages not matching the mailbox / query, displayed for context. +| *msglist_thread_orphan* +: Threaded messages that have a missing parent message. | *dirlist_default* : The default style for directories in the directory list. | *dirlist_unread* @@ -287,6 +289,7 @@ The order that *msglist_\** styles are applied in is, from first to last: . *msglist_result* . *msglist_thread_folded* . *msglist_thread_context* +. *msglist_thread_orphan* . *msglist_marked* So, the marked style will override all other msglist styles. diff --git a/lib/state/templates.go b/lib/state/templates.go index e5206cf0..868f9184 100644 --- a/lib/state/templates.go +++ b/lib/state/templates.go @@ -28,7 +28,7 @@ type DataSetter interface { SetHeaders(*mail.Header, *models.OriginalMail) SetInfo(*models.MessageInfo, int, bool) SetVisual(bool) - SetThreading(string, bool, int, int, bool, bool) + SetThreading(ThreadInfo) SetComposer(Composer) SetAccount(*config.AccountConfig) SetFolder(*models.Directory) @@ -44,6 +44,7 @@ type ThreadInfo struct { Unread int Folded bool Context bool + Orphan bool } type templateData struct { @@ -100,15 +101,8 @@ func (d *templateData) SetVisual(visual bool) { d.visual = visual } -func (d *templateData) SetThreading(prefix string, same bool, count int, - unread int, folded bool, context bool, -) { - d.threadInfo.Prefix = prefix - d.threadInfo.SameSubject = same - d.threadInfo.Count = count - d.threadInfo.Unread = unread - d.threadInfo.Folded = folded - d.threadInfo.Context = context +func (d *templateData) SetThreading(info ThreadInfo) { + d.threadInfo = info } func (d *templateData) SetAccount(acct *config.AccountConfig) { @@ -334,6 +328,10 @@ func (d *templateData) ThreadContext() bool { return d.threadInfo.Context } +func (d *templateData) ThreadOrphan() bool { + return d.threadInfo.Orphan +} + func (d *templateData) Subject() string { var subject string switch { diff --git a/lib/threadbuilder.go b/lib/threadbuilder.go index c18ab3d0..b7dae431 100644 --- a/lib/threadbuilder.go +++ b/lib/threadbuilder.go @@ -165,23 +165,30 @@ func (builder *ThreadBuilder) buildTree(c jwz.Threadable, parent *types.Thread, return } for node := c; node != nil; node = node.GetNext() { - thread := parent - if !node.IsDummy() { - thread = builder.newThread(node, parent) - if rootLevel { - thread.NextSibling = parent.FirstChild - parent.FirstChild = thread - } else { - parent.InsertCmp(thread, bigger) - } + thread := builder.newThread(node, parent, node.IsDummy()) + if rootLevel { + thread.NextSibling = parent.FirstChild + parent.FirstChild = thread + } else { + parent.InsertCmp(thread, bigger) } builder.buildTree(node.GetChild(), thread, bigger, node.IsDummy()) } } -func (builder *ThreadBuilder) newThread(c jwz.Threadable, parent *types.Thread) *types.Thread { +func (builder *ThreadBuilder) newThread(c jwz.Threadable, parent *types.Thread, + hidden bool, +) *types.Thread { + hide := 0 + if hidden { + hide += 1 + } if threadable, ok := c.(*threadable); ok { - return &types.Thread{Uid: threadable.MsgInfo.Uid, Parent: parent} + return &types.Thread{ + Uid: threadable.UID(), + Parent: parent, + Hidden: hide, + } } return nil } @@ -297,6 +304,13 @@ func cleanRefs(m, irp string, refs []string) []string { return cleanRefs } +func (t *threadable) UID() uint32 { + if t.MsgInfo == nil { + return 0 + } + return t.MsgInfo.Uid +} + func (t *threadable) Subject() string { // deactivate threading by subject for now return "" diff --git a/models/templates.go b/models/templates.go index c9b5d5b3..757e934a 100644 --- a/models/templates.go +++ b/models/templates.go @@ -25,6 +25,7 @@ type TemplateData interface { ThreadUnread() int ThreadFolded() bool ThreadContext() bool + ThreadOrphan() bool Subject() string SubjectBase() string Number() int diff --git a/worker/types/thread.go b/worker/types/thread.go index a79a0b2d..42565964 100644 --- a/worker/types/thread.go +++ b/worker/types/thread.go @@ -146,6 +146,9 @@ func getMaxUID(thread *Thread) uint32 { var Uid uint32 _ = thread.Walk(func(t *Thread, _ int, currentErr error) error { + if t.Deleted || t.Hidden > 0 { + return nil + } if t.Uid > Uid { Uid = t.Uid } |