aerc/commands/msg/archive.go
Tim Culverhouse 0c85b5a6cf msglist: remove invalidate from commands which remove messages
Archive, delete, and move all remove messages from the message store.
The commands themselves invalidated the message list. The message list
was also invalidated for every MessagesDeleted message received. Remove
the call in the command logic to reduce redraws of the message list

Signed-off-by: Tim Culverhouse <tim@timculverhouse.com>
Acked-by: Robin Jarry <robin@jarry.cc>
2022-08-01 10:37:44 +02:00

121 lines
2.5 KiB
Go

package msg
import (
"errors"
"fmt"
"path"
"sync"
"time"
"git.sr.ht/~rjarry/aerc/commands"
"git.sr.ht/~rjarry/aerc/logging"
"git.sr.ht/~rjarry/aerc/models"
"git.sr.ht/~rjarry/aerc/widgets"
"git.sr.ht/~rjarry/aerc/worker/types"
)
const (
ARCHIVE_FLAT = "flat"
ARCHIVE_YEAR = "year"
ARCHIVE_MONTH = "month"
)
type Archive struct{}
func init() {
register(Archive{})
}
func (Archive) Aliases() []string {
return []string{"archive"}
}
func (Archive) Complete(aerc *widgets.Aerc, args []string) []string {
valid := []string{"flat", "year", "month"}
return commands.CompletionFromList(aerc, valid, args)
}
func (Archive) Execute(aerc *widgets.Aerc, args []string) error {
if len(args) != 2 {
return errors.New("Usage: archive <flat|year|month>")
}
h := newHelper(aerc)
acct, err := h.account()
if err != nil {
return err
}
store, err := h.store()
if err != nil {
return err
}
msgs, err := h.messages()
if err != nil {
return err
}
archiveDir := acct.AccountConfig().Archive
var uids []uint32
for _, msg := range msgs {
uids = append(uids, msg.Uid)
}
store.ClearVisualMark()
findNextNonDeleted(uids, store)
var uidMap map[string][]uint32
switch args[1] {
case ARCHIVE_MONTH:
uidMap = groupBy(msgs, func(msg *models.MessageInfo) string {
dir := path.Join(archiveDir,
fmt.Sprintf("%d", msg.Envelope.Date.Year()),
fmt.Sprintf("%02d", msg.Envelope.Date.Month()))
return dir
})
case ARCHIVE_YEAR:
uidMap = groupBy(msgs, func(msg *models.MessageInfo) string {
dir := path.Join(archiveDir, fmt.Sprintf("%v",
msg.Envelope.Date.Year()))
return dir
})
case ARCHIVE_FLAT:
uidMap = make(map[string][]uint32)
uidMap[archiveDir] = commands.UidsFromMessageInfos(msgs)
}
var wg sync.WaitGroup
wg.Add(len(uidMap))
success := true
for dir, uids := range uidMap {
store.Move(uids, dir, true, func(
msg types.WorkerMessage) {
switch msg := msg.(type) {
case *types.Done:
wg.Done()
case *types.Error:
aerc.PushError(msg.Error.Error())
success = false
wg.Done()
store.Remark()
}
})
}
// we need to do that in the background, else we block the main thread
go func() {
defer logging.PanicHandler()
wg.Wait()
if success {
aerc.PushStatus("Messages archived.", 10*time.Second)
}
}()
return nil
}
func groupBy(msgs []*models.MessageInfo,
grouper func(*models.MessageInfo) string) map[string][]uint32 {
m := make(map[string][]uint32)
for _, msg := range msgs {
group := grouper(msg)
m[group] = append(m[group], msg.Uid)
}
return m
}