mark: (un)mark message threads

Mark or unmark the shown message threads. Threads must be available in the
message store. Use the -T option for the mark or unmark commands. Can be
used in combination with the toggle flag (-t).

Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
Koni Marti 2022-08-08 22:21:45 +02:00 committed by Robin Jarry
parent b12dd9f926
commit 117f99e187
4 changed files with 85 additions and 5 deletions

View File

@ -32,7 +32,7 @@ func (Mark) Execute(aerc *widgets.Aerc, args []string) error {
return err
}
marker := store.Marker()
opts, _, err := getopt.Getopts(args, "atvV")
opts, _, err := getopt.Getopts(args, "atvVT")
if err != nil {
return err
}
@ -40,6 +40,7 @@ func (Mark) Execute(aerc *widgets.Aerc, args []string) error {
var toggle bool
var visual bool
var clearVisual bool
var thread bool
for _, opt := range opts {
switch opt.Option {
case 'a':
@ -51,9 +52,23 @@ func (Mark) Execute(aerc *widgets.Aerc, args []string) error {
visual = true
case 't':
toggle = true
case 'T':
thread = true
}
}
if thread && len(store.Threads()) == 0 {
return fmt.Errorf("No threads found")
}
if thread && all {
return fmt.Errorf("-a and -T are mutually exclusive")
}
if thread && visual {
return fmt.Errorf("-v and -T are mutually exclusive")
}
switch args[0] {
case "mark":
if all && visual {
@ -77,7 +92,13 @@ func (Mark) Execute(aerc *widgets.Aerc, args []string) error {
marker.ToggleVisualMark(clearVisual)
return nil
default:
modFunc(selected.Uid)
if thread {
for _, uid := range store.SelectedThread().Root().Uids() {
modFunc(uid)
}
} else {
modFunc(selected.Uid)
}
return nil
}
@ -97,11 +118,17 @@ func (Mark) Execute(aerc *widgets.Aerc, args []string) error {
marker.ClearVisualMark()
return nil
default:
marker.Unmark(selected.Uid)
if thread {
for _, uid := range store.SelectedThread().Root().Uids() {
marker.Unmark(uid)
}
} else {
marker.Unmark(selected.Uid)
}
return nil
}
case "remark":
if all || visual || toggle {
if all || visual || toggle || thread {
return fmt.Errorf("Usage: :remark")
}
marker.Remark()

View File

@ -402,7 +402,7 @@ message list, the message in the message viewer, etc).
*-a*: Save all attachments. Individual filenames cannot be specified.
*mark* [-atv]
*mark* [-atvT]
Marks messages. Commands will execute on all marked messages instead of the
highlighted one if applicable. The flags below can be combined as needed.
@ -414,6 +414,8 @@ message list, the message in the message viewer, etc).
*-V*: Same as -v but does not clear existing selection
*-T*: Marks the displayed message thread of the selected message.
*unmark* [-at]
Unmarks messages. The flags below can be combined as needed.

View File

@ -411,6 +411,28 @@ func (store *MessageStore) runThreadBuilder() {
})
}
// SelectedThread returns the thread with the UID from the selected message
func (store *MessageStore) SelectedThread() *types.Thread {
var thread *types.Thread
for _, root := range store.Threads() {
found := false
err := root.Walk(func(t *types.Thread, _ int, _ error) error {
if t.Uid == store.SelectedUid() {
thread = t
found = true
}
return nil
})
if err != nil {
logging.Errorf("SelectedThread failed: %w", err)
}
if found {
break
}
}
return thread
}
func (store *MessageStore) Delete(uids []uint32,
cb func(msg types.WorkerMessage),
) {

View File

@ -4,6 +4,8 @@ import (
"errors"
"fmt"
"sort"
"git.sr.ht/~rjarry/aerc/logging"
)
type Thread struct {
@ -48,6 +50,33 @@ func (t *Thread) Walk(walkFn NewThreadWalkFn) error {
return err
}
// Root returns the root thread of the thread tree
func (t *Thread) Root() *Thread {
if t == nil {
return nil
}
var iter *Thread
for iter = t; iter.Parent != nil; iter = iter.Parent {
}
return iter
}
// Uids returns all associated uids for the given thread and its children
func (t *Thread) Uids() []uint32 {
if t == nil {
return nil
}
uids := make([]uint32, 0)
err := t.Walk(func(node *Thread, _ int, _ error) error {
uids = append(uids, node.Uid)
return nil
})
if err != nil {
logging.Errorf("walk to collect uids failed: %w", err)
}
return uids
}
func (t *Thread) String() string {
if t == nil {
return "<nil>"