aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--commands/commands_test.go1
-rw-r--r--config/aerc.conf8
-rw-r--r--config/style.go4
-rw-r--r--config/templates.go1
-rw-r--r--config/ui.go1
-rw-r--r--doc/aerc-config.5.scd6
-rw-r--r--lib/msgstore.go4
-rw-r--r--lib/state/templates.go10
-rw-r--r--models/templates.go1
-rw-r--r--widgets/account.go1
-rw-r--r--widgets/msglist.go14
-rw-r--r--worker/notmuch/lib/database.go19
-rw-r--r--worker/notmuch/worker.go4
-rw-r--r--worker/types/messages.go1
-rw-r--r--worker/types/thread.go4
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.