diff options
-rw-r--r-- | commands/commands_test.go | 1 | ||||
-rw-r--r-- | config/aerc.conf | 8 | ||||
-rw-r--r-- | config/style.go | 4 | ||||
-rw-r--r-- | config/templates.go | 1 | ||||
-rw-r--r-- | config/ui.go | 1 | ||||
-rw-r--r-- | doc/aerc-config.5.scd | 6 | ||||
-rw-r--r-- | lib/msgstore.go | 4 | ||||
-rw-r--r-- | lib/state/templates.go | 10 | ||||
-rw-r--r-- | models/templates.go | 1 | ||||
-rw-r--r-- | widgets/account.go | 1 | ||||
-rw-r--r-- | widgets/msglist.go | 14 | ||||
-rw-r--r-- | worker/notmuch/lib/database.go | 19 | ||||
-rw-r--r-- | worker/notmuch/worker.go | 4 | ||||
-rw-r--r-- | worker/types/messages.go | 1 | ||||
-rw-r--r-- | worker/types/thread.go | 4 |
15 files changed, 64 insertions, 15 deletions
diff --git a/commands/commands_test.go b/commands/commands_test.go index a1518aaa..7edd0228 100644 --- a/commands/commands_test.go +++ b/commands/commands_test.go @@ -77,6 +77,7 @@ func (d *dummyData) Header(string) string { return "" } func (d *dummyData) ThreadPrefix() string { return "└─>" } func (d *dummyData) ThreadCount() int { return 0 } func (d *dummyData) ThreadFolded() bool { return false } +func (d *dummyData) ThreadContext() bool { return false } func (d *dummyData) Subject() string { return "Re: [PATCH] hey" } func (d *dummyData) SubjectBase() string { return "[PATCH] hey" } func (d *dummyData) Number() int { return 0 } diff --git a/config/aerc.conf b/config/aerc.conf index 00c8501f..4b4e7cb6 100644 --- a/config/aerc.conf +++ b/config/aerc.conf @@ -290,6 +290,14 @@ # Default: false #force-client-threads=false +# Show thread context enables messages which do not match the current query (or +# belong to the current mailbox) to be shown for context. These messages can be +# styled separately using "msglist_thread_context" in a styleset. This feature +# is not supported by all backends +# +# Default: false +#show-thread-context=false + # Debounce client-side thread building # # Default: 50ms diff --git a/config/style.go b/config/style.go index 3f117fc0..8a88dcfc 100644 --- a/config/style.go +++ b/config/style.go @@ -41,6 +41,7 @@ const ( STYLE_MSGLIST_THREAD_FOLDED STYLE_MSGLIST_GUTTER STYLE_MSGLIST_PILL + STYLE_MSGLIST_THREAD_CONTEXT STYLE_DIRLIST_DEFAULT STYLE_DIRLIST_UNREAD @@ -89,7 +90,8 @@ var StyleNames = map[string]StyleObject{ "msglist_gutter": STYLE_MSGLIST_GUTTER, "msglist_pill": STYLE_MSGLIST_PILL, - "msglist_thread_folded": STYLE_MSGLIST_THREAD_FOLDED, + "msglist_thread_folded": STYLE_MSGLIST_THREAD_FOLDED, + "msglist_thread_context": STYLE_MSGLIST_THREAD_CONTEXT, "dirlist_default": STYLE_DIRLIST_DEFAULT, "dirlist_unread": STYLE_DIRLIST_UNREAD, diff --git a/config/templates.go b/config/templates.go index 3f0249df..e2adeac2 100644 --- a/config/templates.go +++ b/config/templates.go @@ -78,6 +78,7 @@ func (d *dummyData) Header(string) string { return "" } func (d *dummyData) ThreadPrefix() string { return "└─>" } func (d *dummyData) ThreadCount() int { return 0 } func (d *dummyData) ThreadFolded() bool { return false } +func (d *dummyData) ThreadContext() 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/config/ui.go b/config/ui.go index 0479c13b..3b637278 100644 --- a/config/ui.go +++ b/config/ui.go @@ -41,6 +41,7 @@ type UIConfig struct { ThreadingEnabled bool `ini:"threading-enabled"` ForceClientThreads bool `ini:"force-client-threads"` ClientThreadsDelay time.Duration `ini:"client-threads-delay" default:"50ms"` + ThreadContext bool `ini:"show-thread-context"` FuzzyComplete bool `ini:"fuzzy-complete"` NewMessageBell bool `ini:"new-message-bell" default:"true"` Spinner string `ini:"spinner" default:"[..] , [..] , [..] , [..] , [..], [..] , [..] , [..] "` diff --git a/doc/aerc-config.5.scd b/doc/aerc-config.5.scd index cace2beb..b6855c7a 100644 --- a/doc/aerc-config.5.scd +++ b/doc/aerc-config.5.scd @@ -431,6 +431,12 @@ These options are configured in the *[ui]* section of _aerc.conf_. Default: _50ms_ +*show-thread-context* = _true_|_false_ + Enable showing of thread context. Note: this is not supported by all + backends. + + Default: _false_ + ## CONTEXTUAL UI CONFIGURATION The UI configuration can be specialized for accounts, specific mail diff --git a/lib/msgstore.go b/lib/msgstore.go index 01b78289..6186b195 100644 --- a/lib/msgstore.go +++ b/lib/msgstore.go @@ -49,6 +49,7 @@ type MessageStore struct { threadedView bool reverseThreadOrder bool + threadContext bool sortThreadSiblings bool buildThreads bool builder *ThreadBuilder @@ -87,6 +88,7 @@ func NewMessageStore(worker *types.Worker, reverseOrder bool, reverseThreadOrder bool, sortThreadSiblings bool, triggerNewEmail func(*models.MessageInfo), triggerDirectoryChange func(), onSelect func(*models.MessageInfo), + threadContext bool, ) *MessageStore { if !worker.Backend.Capabilities().Thread { clientThreads = true @@ -104,6 +106,7 @@ func NewMessageStore(worker *types.Worker, threadedView: thread, buildThreads: clientThreads, + threadContext: threadContext, reverseThreadOrder: reverseThreadOrder, sortThreadSiblings: sortThreadSiblings, @@ -831,6 +834,7 @@ func (store *MessageStore) Sort(criteria []*types.SortCriterion, cb func(types.W Context: store.ctx, SortCriteria: criteria, FilterCriteria: store.filter, + ThreadContext: store.threadContext, }, handle_return) } else { store.worker.PostAction(&types.FetchDirectoryContents{ diff --git a/lib/state/templates.go b/lib/state/templates.go index fbe5aa4a..88c5eeae 100644 --- a/lib/state/templates.go +++ b/lib/state/templates.go @@ -20,7 +20,7 @@ type DataSetter interface { Data() models.TemplateData SetHeaders(*mail.Header, *models.OriginalMail) SetInfo(*models.MessageInfo, int, bool) - SetThreading(string, bool, int, bool) + SetThreading(string, bool, int, bool, bool) SetComposer(Composer) SetAccount(*config.AccountConfig) SetFolder(*models.Directory) @@ -34,6 +34,7 @@ type ThreadInfo struct { Prefix string Count int Folded bool + Context bool } type templateData struct { @@ -86,12 +87,13 @@ func (d *templateData) SetInfo(info *models.MessageInfo, num int, marked bool, } func (d *templateData) SetThreading(prefix string, same bool, count int, - folded bool, + folded bool, context bool, ) { d.threadInfo.Prefix = prefix d.threadInfo.SameSubject = same d.threadInfo.Count = count d.threadInfo.Folded = folded + d.threadInfo.Context = context } func (d *templateData) SetAccount(acct *config.AccountConfig) { @@ -300,6 +302,10 @@ func (d *templateData) ThreadFolded() bool { return d.threadInfo.Folded } +func (d *templateData) ThreadContext() bool { + return d.threadInfo.Context +} + func (d *templateData) Subject() string { var subject string switch { diff --git a/models/templates.go b/models/templates.go index 0c684e86..ac6d410a 100644 --- a/models/templates.go +++ b/models/templates.go @@ -22,6 +22,7 @@ type TemplateData interface { ThreadPrefix() string ThreadCount() int ThreadFolded() bool + ThreadContext() bool Subject() string SubjectBase() string Number() int diff --git a/widgets/account.go b/widgets/account.go index 982d75f8..7e380996 100644 --- a/widgets/account.go +++ b/widgets/account.go @@ -255,6 +255,7 @@ func (acct *AccountView) newStore(name string) *lib.MessageStore { } }, acct.updateSplitView, + acct.dirlist.UiConfig(name).ThreadContext, ) store.SetMarker(marker.New(store)) return store diff --git a/widgets/msglist.go b/widgets/msglist.go index dcb4cd31..3187b5d5 100644 --- a/widgets/msglist.go +++ b/widgets/msglist.go @@ -209,8 +209,13 @@ func addMessage( } // folded thread templateData, ok := data.(models.TemplateData) - if ok && templateData.ThreadFolded() { - params.styles = append(params.styles, config.STYLE_MSGLIST_THREAD_FOLDED) + if ok { + if templateData.ThreadFolded() { + params.styles = append(params.styles, config.STYLE_MSGLIST_THREAD_FOLDED) + } + if templateData.ThreadContext() { + params.styles = append(params.styles, config.STYLE_MSGLIST_THREAD_CONTEXT) + } } // marked message marked := store.Marker().IsMarked(msg.Uid) @@ -476,7 +481,7 @@ func newThreadView(store *lib.MessageStore) *threadView { } func (t *threadView) Update(data state.DataSetter, uid uint32) { - prefix, same, count, folded := "", false, 0, false + prefix, same, count, folded, context := "", false, 0, false, false thread, err := t.store.Thread(uid) if thread != nil && err == nil { prefix = threadPrefix(thread, t.reverse, true) @@ -486,6 +491,7 @@ func (t *threadView) Update(data state.DataSetter, uid uint32) { t.prevSubj = subject count = countThreads(thread) folded = thread.FirstChild != nil && thread.FirstChild.Hidden + context = thread.Context } - data.SetThreading(prefix, same, count, folded) + data.SetThreading(prefix, same, count, folded, context) } diff --git a/worker/notmuch/lib/database.go b/worker/notmuch/lib/database.go index 9a6689c4..e7914156 100644 --- a/worker/notmuch/lib/database.go +++ b/worker/notmuch/lib/database.go @@ -111,7 +111,7 @@ func (db *DB) MsgIDsFromQuery(ctx context.Context, q string) ([]string, error) { return msgIDs, err } -func (db *DB) ThreadsFromQuery(ctx context.Context, q string) ([]*types.Thread, error) { +func (db *DB) ThreadsFromQuery(ctx context.Context, q string, entireThread bool) ([]*types.Thread, error) { query, err := db.newQuery(q) if err != nil { return nil, err @@ -136,7 +136,7 @@ func (db *DB) ThreadsFromQuery(ctx context.Context, q string) ([]*types.Thread, default: thread := threads.Thread() tlm := thread.TopLevelMessages() - root := db.makeThread(nil, &tlm) + root := db.makeThread(nil, &tlm, entireThread) res = append(res, root) tlm.Close() thread.Close() @@ -306,7 +306,7 @@ func (db *DB) KeyFromUid(uid uint32) (string, bool) { return db.uidStore.GetKey(uid) } -func (db *DB) makeThread(parent *types.Thread, msgs *notmuch.Messages) *types.Thread { +func (db *DB) makeThread(parent *types.Thread, msgs *notmuch.Messages, threadContext bool) *types.Thread { var lastSibling *types.Thread for msgs.Next() { msg := msgs.Message() @@ -319,14 +319,19 @@ func (db *DB) makeThread(parent *types.Thread, msgs *notmuch.Messages) *types.Th } replies := msg.Replies() defer replies.Close() - if !match { - parent = db.makeThread(parent, &replies) + if !match && !threadContext { + parent = db.makeThread(parent, &replies, threadContext) continue } node := &types.Thread{ Uid: db.uidStore.GetOrInsert(msgID), Parent: parent, - Hidden: !match, + } + switch threadContext { + case true: + node.Context = !match + default: + node.Hidden = !match } if parent != nil && parent.FirstChild == nil { parent.FirstChild = node @@ -340,7 +345,7 @@ func (db *DB) makeThread(parent *types.Thread, msgs *notmuch.Messages) *types.Th lastSibling.NextSibling = node } lastSibling = node - db.makeThread(node, &replies) + db.makeThread(node, &replies, threadContext) } // We want to return the root node diff --git a/worker/notmuch/worker.go b/worker/notmuch/worker.go index d1eb69d0..2f601528 100644 --- a/worker/notmuch/worker.go +++ b/worker/notmuch/worker.go @@ -635,6 +635,7 @@ func (w *worker) emitDirectoryContents(parent types.WorkerMessage) error { func (w *worker) emitDirectoryThreaded(parent types.WorkerMessage) error { query := w.query ctx := context.Background() + threadContext := false if msg, ok := parent.(*types.FetchDirectoryThreaded); ok { log.Debugf("filter input: '%v'", msg.FilterCriteria) s, err := translate(msg.FilterCriteria) @@ -646,8 +647,9 @@ func (w *worker) emitDirectoryThreaded(parent types.WorkerMessage) error { log.Debugf("filter query: '%s'", query) } ctx = msg.Context + threadContext = msg.ThreadContext } - threads, err := w.db.ThreadsFromQuery(ctx, query) + threads, err := w.db.ThreadsFromQuery(ctx, query, threadContext) if err != nil { return err } diff --git a/worker/types/messages.go b/worker/types/messages.go index 26408684..7cab9a7a 100644 --- a/worker/types/messages.go +++ b/worker/types/messages.go @@ -115,6 +115,7 @@ type FetchDirectoryThreaded struct { Context context.Context SortCriteria []*SortCriterion FilterCriteria []string + ThreadContext bool } type SearchDirectory struct { diff --git a/worker/types/thread.go b/worker/types/thread.go index 2f739bc2..75651280 100644 --- a/worker/types/thread.go +++ b/worker/types/thread.go @@ -17,6 +17,10 @@ type Thread struct { Hidden bool // if this flag is set the message isn't rendered in the UI Deleted bool // if this flag is set the message was deleted + + // Context indicates the message doesn't match the mailbox / query but + // is displayed for context + Context bool } // AddChild appends the child node at the end of the existing children of t. |