msglist: display reversed thread ordering

Reverse the ordering of the message threads.

Implements: https://todo.sr.ht/~rjarry/aerc/54
Signed-off-by: Koni Marti <koni.marti@gmail.com>
Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
Koni Marti 2022-10-20 16:43:45 +02:00 committed by Robin Jarry
parent 006e10357b
commit ae99f4c5bb
2 changed files with 65 additions and 56 deletions

View file

@ -249,7 +249,7 @@ func (dt *DirectoryTree) countVisible(list []*types.Thread) (n int) {
func (dt *DirectoryTree) displayText(node *types.Thread) string {
elems := strings.Split(dt.treeDirs[getAnyUid(node)], dt.pathSeparator)
return fmt.Sprintf("%s%s%s", threadPrefix(node), getFlag(node), elems[countLevels(node)])
return fmt.Sprintf("%s%s%s", threadPrefix(node, false), getFlag(node), elems[countLevels(node)])
}
func (dt *DirectoryTree) getDirectory(node *types.Thread) string {

View file

@ -12,6 +12,7 @@ import (
"git.sr.ht/~rjarry/aerc/config"
"git.sr.ht/~rjarry/aerc/lib"
"git.sr.ht/~rjarry/aerc/lib/format"
"git.sr.ht/~rjarry/aerc/lib/iterator"
"git.sr.ht/~rjarry/aerc/lib/ui"
"git.sr.ht/~rjarry/aerc/logging"
"git.sr.ht/~rjarry/aerc/models"
@ -88,57 +89,61 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
row int = 0
)
if store.ThreadedView() {
iter := store.ThreadsIterator()
var i int = 0
for iter.Next() {
thread := iter.Value().(*types.Thread)
var lastSubject string
err := thread.Walk(func(t *types.Thread, _ int, currentErr error) error {
if currentErr != nil {
return currentErr
createBaseCtx := func(uid uint32, row int) format.Ctx {
return format.Ctx{
FromAddress: acct.acct.From,
AccountName: acct.Name(),
MsgInfo: store.Messages[uid],
MsgNum: row,
MsgIsMarked: store.Marker().IsMarked(uid),
}
}
if store.ThreadedView() {
var (
lastSubject string
prevThread *types.Thread
i int = 0
)
factory := iterator.NewFactory(!store.ReverseThreadOrder())
threadLoop:
for iter := store.ThreadsIterator(); iter.Next(); {
var cur []*types.Thread
err := iter.Value().(*types.Thread).Walk(
func(t *types.Thread, _ int, _ error,
) error {
if t.Hidden || t.Deleted {
return nil
}
if i < ml.Scroll() {
i++
return nil
}
i++
msg := store.Messages[t.Uid]
var prefix string
var subject string
var normalizedSubject string
if msg != nil {
prefix = threadPrefix(t)
if msg.Envelope != nil {
subject = msg.Envelope.Subject
normalizedSubject, _ = sortthread.GetBaseSubject(subject)
}
}
fmtCtx := format.Ctx{
FromAddress: acct.acct.From,
AccountName: acct.Name(),
MsgInfo: msg,
MsgNum: row,
MsgIsMarked: store.Marker().IsMarked(t.Uid),
ThreadPrefix: prefix,
ThreadSameSubject: normalizedSubject == lastSubject,
}
if ml.drawRow(textWidth, ctx, t.Uid, row, &needsHeaders, fmtCtx) {
return types.ErrSkipThread
}
lastSubject = normalizedSubject
row++
cur = append(cur, t)
return nil
})
if err != nil {
logging.Warnf("failed to walk threads: %v", err)
logging.Errorf("thread walk: %v", err)
}
for curIter := factory.NewIterator(cur); curIter.Next(); {
if i < ml.Scroll() {
i++
continue
}
if thread := curIter.Value().(*types.Thread); thread != nil {
fmtCtx := createBaseCtx(thread.Uid, row)
fmtCtx.ThreadPrefix = threadPrefix(thread,
store.ReverseThreadOrder())
if fmtCtx.MsgInfo != nil && fmtCtx.MsgInfo.Envelope != nil {
baseSubject, _ := sortthread.GetBaseSubject(
fmtCtx.MsgInfo.Envelope.Subject)
fmtCtx.ThreadSameSubject = baseSubject == lastSubject &&
sameParent(thread, prevThread) &&
!isParent(thread)
lastSubject = baseSubject
prevThread = thread
}
if ml.drawRow(textWidth, ctx, thread.Uid, row, &needsHeaders, fmtCtx) {
break threadLoop
}
row += 1
}
if row >= ctx.Height() {
break
}
}
} else {
@ -148,15 +153,7 @@ func (ml *MessageList) Draw(ctx *ui.Context) {
continue
}
uid := iter.Value().(uint32)
msg := store.Messages[uid]
fmtCtx := format.Ctx{
FromAddress: acct.acct.From,
AccountName: acct.Name(),
MsgInfo: msg,
MsgNum: row,
MsgIsMarked: store.Marker().IsMarked(uid),
}
fmtCtx := createBaseCtx(uid, row)
if ml.drawRow(textWidth, ctx, uid, row, &needsHeaders, fmtCtx) {
break
}
@ -429,15 +426,19 @@ func (ml *MessageList) drawEmptyMessage(ctx *ui.Context) {
uiConfig.GetStyle(config.STYLE_MSGLIST_DEFAULT), "%s", msg)
}
func threadPrefix(t *types.Thread) string {
func threadPrefix(t *types.Thread, reverse bool) string {
var arrow string
if t.Parent != nil {
if t.NextSibling != nil {
arrow = "├─>"
} else {
if reverse {
arrow = "┌─>"
} else {
arrow = "└─>"
}
}
}
var prefix []string
for n := t; n.Parent != nil; n = n.Parent {
if n.Parent.NextSibling != nil {
@ -458,3 +459,11 @@ func threadPrefix(t *types.Thread) string {
ps := strings.Join(prefix, "")
return fmt.Sprintf("%v%v", ps, arrow)
}
func sameParent(left, right *types.Thread) bool {
return left.Root() == right.Root()
}
func isParent(t *types.Thread) bool {
return t == t.Root()
}