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:
parent
b12dd9f926
commit
117f99e187
4 changed files with 85 additions and 5 deletions
|
@ -32,7 +32,7 @@ func (Mark) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
marker := store.Marker()
|
marker := store.Marker()
|
||||||
opts, _, err := getopt.Getopts(args, "atvV")
|
opts, _, err := getopt.Getopts(args, "atvVT")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -40,6 +40,7 @@ func (Mark) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
var toggle bool
|
var toggle bool
|
||||||
var visual bool
|
var visual bool
|
||||||
var clearVisual bool
|
var clearVisual bool
|
||||||
|
var thread bool
|
||||||
for _, opt := range opts {
|
for _, opt := range opts {
|
||||||
switch opt.Option {
|
switch opt.Option {
|
||||||
case 'a':
|
case 'a':
|
||||||
|
@ -51,9 +52,23 @@ func (Mark) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
visual = true
|
visual = true
|
||||||
case 't':
|
case 't':
|
||||||
toggle = true
|
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] {
|
switch args[0] {
|
||||||
case "mark":
|
case "mark":
|
||||||
if all && visual {
|
if all && visual {
|
||||||
|
@ -77,7 +92,13 @@ func (Mark) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
marker.ToggleVisualMark(clearVisual)
|
marker.ToggleVisualMark(clearVisual)
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
modFunc(selected.Uid)
|
if thread {
|
||||||
|
for _, uid := range store.SelectedThread().Root().Uids() {
|
||||||
|
modFunc(uid)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
modFunc(selected.Uid)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,11 +118,17 @@ func (Mark) Execute(aerc *widgets.Aerc, args []string) error {
|
||||||
marker.ClearVisualMark()
|
marker.ClearVisualMark()
|
||||||
return nil
|
return nil
|
||||||
default:
|
default:
|
||||||
marker.Unmark(selected.Uid)
|
if thread {
|
||||||
|
for _, uid := range store.SelectedThread().Root().Uids() {
|
||||||
|
marker.Unmark(uid)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
marker.Unmark(selected.Uid)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
case "remark":
|
case "remark":
|
||||||
if all || visual || toggle {
|
if all || visual || toggle || thread {
|
||||||
return fmt.Errorf("Usage: :remark")
|
return fmt.Errorf("Usage: :remark")
|
||||||
}
|
}
|
||||||
marker.Remark()
|
marker.Remark()
|
||||||
|
|
|
@ -402,7 +402,7 @@ message list, the message in the message viewer, etc).
|
||||||
|
|
||||||
*-a*: Save all attachments. Individual filenames cannot be specified.
|
*-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
|
Marks messages. Commands will execute on all marked messages instead of the
|
||||||
highlighted one if applicable. The flags below can be combined as needed.
|
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
|
*-V*: Same as -v but does not clear existing selection
|
||||||
|
|
||||||
|
*-T*: Marks the displayed message thread of the selected message.
|
||||||
|
|
||||||
*unmark* [-at]
|
*unmark* [-at]
|
||||||
Unmarks messages. The flags below can be combined as needed.
|
Unmarks messages. The flags below can be combined as needed.
|
||||||
|
|
||||||
|
|
|
@ -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,
|
func (store *MessageStore) Delete(uids []uint32,
|
||||||
cb func(msg types.WorkerMessage),
|
cb func(msg types.WorkerMessage),
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -4,6 +4,8 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
|
"git.sr.ht/~rjarry/aerc/logging"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Thread struct {
|
type Thread struct {
|
||||||
|
@ -48,6 +50,33 @@ func (t *Thread) Walk(walkFn NewThreadWalkFn) error {
|
||||||
return err
|
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 {
|
func (t *Thread) String() string {
|
||||||
if t == nil {
|
if t == nil {
|
||||||
return "<nil>"
|
return "<nil>"
|
||||||
|
|
Loading…
Reference in a new issue