fc9ccc3000
We made a new type out of go-message/mail.Address without any real reason. This suddenly made it necessary to convert from one to the other without actually having any benefit whatsoever. This commit gets rid of the additional type
153 lines
4.1 KiB
Go
153 lines
4.1 KiB
Go
package lib
|
|
|
|
import (
|
|
"sort"
|
|
"strings"
|
|
|
|
"git.sr.ht/~sircmpwn/aerc/models"
|
|
"git.sr.ht/~sircmpwn/aerc/worker/types"
|
|
"github.com/emersion/go-message/mail"
|
|
)
|
|
|
|
func Sort(messageInfos []*models.MessageInfo,
|
|
criteria []*types.SortCriterion) ([]uint32, error) {
|
|
// loop through in reverse to ensure we sort by non-primary fields first
|
|
for i := len(criteria) - 1; i >= 0; i-- {
|
|
criterion := criteria[i]
|
|
switch criterion.Field {
|
|
case types.SortArrival:
|
|
sortSlice(criterion, messageInfos, func(i, j int) bool {
|
|
return messageInfos[i].InternalDate.Before(messageInfos[j].InternalDate)
|
|
})
|
|
case types.SortCc:
|
|
sortAddresses(messageInfos, criterion,
|
|
func(msgInfo *models.MessageInfo) []*mail.Address {
|
|
return msgInfo.Envelope.Cc
|
|
})
|
|
case types.SortDate:
|
|
sortSlice(criterion, messageInfos, func(i, j int) bool {
|
|
return messageInfos[i].Envelope.Date.Before(messageInfos[j].Envelope.Date)
|
|
})
|
|
case types.SortFrom:
|
|
sortAddresses(messageInfos, criterion,
|
|
func(msgInfo *models.MessageInfo) []*mail.Address {
|
|
return msgInfo.Envelope.From
|
|
})
|
|
case types.SortRead:
|
|
sortFlags(messageInfos, criterion, models.SeenFlag)
|
|
case types.SortSize:
|
|
sortSlice(criterion, messageInfos, func(i, j int) bool {
|
|
return messageInfos[i].Size < messageInfos[j].Size
|
|
})
|
|
case types.SortSubject:
|
|
sortStrings(messageInfos, criterion,
|
|
func(msgInfo *models.MessageInfo) string {
|
|
subject := strings.ToLower(msgInfo.Envelope.Subject)
|
|
subject = strings.TrimPrefix(subject, "re: ")
|
|
return strings.TrimPrefix(subject, "fwd: ")
|
|
})
|
|
case types.SortTo:
|
|
sortAddresses(messageInfos, criterion,
|
|
func(msgInfo *models.MessageInfo) []*mail.Address {
|
|
return msgInfo.Envelope.To
|
|
})
|
|
}
|
|
}
|
|
var uids []uint32
|
|
// copy in reverse as msgList displays backwards
|
|
for i := len(messageInfos) - 1; i >= 0; i-- {
|
|
uids = append(uids, messageInfos[i].Uid)
|
|
}
|
|
return uids, nil
|
|
}
|
|
|
|
func sortAddresses(messageInfos []*models.MessageInfo, criterion *types.SortCriterion,
|
|
getValue func(*models.MessageInfo) []*mail.Address) {
|
|
sortSlice(criterion, messageInfos, func(i, j int) bool {
|
|
addressI, addressJ := getValue(messageInfos[i]), getValue(messageInfos[j])
|
|
var firstI, firstJ *mail.Address
|
|
if len(addressI) > 0 {
|
|
firstI = addressI[0]
|
|
}
|
|
if len(addressJ) > 0 {
|
|
firstJ = addressJ[0]
|
|
}
|
|
if firstI == nil && firstJ == nil {
|
|
return false
|
|
} else if firstI == nil && firstJ != nil {
|
|
return false
|
|
} else if firstI != nil && firstJ == nil {
|
|
return true
|
|
} else /* firstI != nil && firstJ != nil */ {
|
|
getName := func(addr *mail.Address) string {
|
|
if addr.Name != "" {
|
|
return addr.Name
|
|
} else {
|
|
return addr.Address
|
|
}
|
|
}
|
|
return getName(firstI) < getName(firstJ)
|
|
}
|
|
})
|
|
}
|
|
|
|
func sortFlags(messageInfos []*models.MessageInfo, criterion *types.SortCriterion,
|
|
testFlag models.Flag) {
|
|
var slice []*boolStore
|
|
for _, msgInfo := range messageInfos {
|
|
flagPresent := false
|
|
for _, flag := range msgInfo.Flags {
|
|
if flag == testFlag {
|
|
flagPresent = true
|
|
}
|
|
}
|
|
slice = append(slice, &boolStore{
|
|
Value: flagPresent,
|
|
MsgInfo: msgInfo,
|
|
})
|
|
}
|
|
sortSlice(criterion, slice, func(i, j int) bool {
|
|
valI, valJ := slice[i].Value, slice[j].Value
|
|
return valI && !valJ
|
|
})
|
|
for i := 0; i < len(messageInfos); i++ {
|
|
messageInfos[i] = slice[i].MsgInfo
|
|
}
|
|
}
|
|
|
|
func sortStrings(messageInfos []*models.MessageInfo, criterion *types.SortCriterion,
|
|
getValue func(*models.MessageInfo) string) {
|
|
var slice []*lexiStore
|
|
for _, msgInfo := range messageInfos {
|
|
slice = append(slice, &lexiStore{
|
|
Value: getValue(msgInfo),
|
|
MsgInfo: msgInfo,
|
|
})
|
|
}
|
|
sortSlice(criterion, slice, func(i, j int) bool {
|
|
return slice[i].Value < slice[j].Value
|
|
})
|
|
for i := 0; i < len(messageInfos); i++ {
|
|
messageInfos[i] = slice[i].MsgInfo
|
|
}
|
|
}
|
|
|
|
type lexiStore struct {
|
|
Value string
|
|
MsgInfo *models.MessageInfo
|
|
}
|
|
|
|
type boolStore struct {
|
|
Value bool
|
|
MsgInfo *models.MessageInfo
|
|
}
|
|
|
|
func sortSlice(criterion *types.SortCriterion, slice interface{}, less func(i, j int) bool) {
|
|
if criterion.Reverse {
|
|
sort.SliceStable(slice, func(i, j int) bool {
|
|
return less(j, i)
|
|
})
|
|
} else {
|
|
sort.SliceStable(slice, less)
|
|
}
|
|
}
|