~rjarry/aerc

ref: dc2a2c2dfd6dc327fe40fbf2da922ef6c3d520be aerc/worker/types/thread.go -rw-r--r-- 1.9 KiB
dc2a2c2d — y0ast messages: allow displaying email threads 6 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package types

import (
	"errors"
	"fmt"
)

type Thread struct {
	Uid         uint32
	Parent      *Thread
	PrevSibling *Thread
	NextSibling *Thread
	FirstChild  *Thread

	Hidden  bool // if this flag is set the message isn't rendered in the UI
	Deleted bool // if this flag is set the message was deleted
}

func (t *Thread) Walk(walkFn NewThreadWalkFn) error {
	err := newWalk(t, walkFn, 0, nil)
	if err == ErrSkipThread {
		return nil
	}
	return err
}

func (t *Thread) String() string {
	if t == nil {
		return "<nil>"
	}
	parent := -1
	if t.Parent != nil {
		parent = int(t.Parent.Uid)
	}
	next := -1
	if t.NextSibling != nil {
		next = int(t.NextSibling.Uid)
	}
	child := -1
	if t.FirstChild != nil {
		child = int(t.FirstChild.Uid)
	}
	return fmt.Sprintf(
		"[%d] (parent:%v, next:%v, child:%v)",
		t.Uid, parent, next, child,
	)
}

func newWalk(node *Thread, walkFn NewThreadWalkFn, lvl int, ce error) error {
	if node == nil {
		return nil
	}
	err := walkFn(node, lvl, ce)
	if err != nil {
		return err
	}
	for child := node.FirstChild; child != nil; child = child.NextSibling {
		err = newWalk(child, walkFn, lvl+1, err)
		if err == ErrSkipThread {
			err = nil
			continue
		} else if err != nil {
			return err
		}
	}
	return nil
}

var ErrSkipThread = errors.New("skip this Thread")

type NewThreadWalkFn func(t *Thread, level int, currentErr error) error

//Implement interface to be able to sort threads by newest (max UID)
type ByUID []*Thread

func getMaxUID(thread *Thread) uint32 {
	// TODO: should we make this part of the Thread type to avoid recomputation?
	var Uid uint32

	thread.Walk(func(t *Thread, _ int, currentErr error) error {
		if t.Uid > Uid {
			Uid = t.Uid
		}
		return nil
	})
	return Uid
}

func (s ByUID) Len() int {
	return len(s)
}
func (s ByUID) Swap(i, j int) {
	s[i], s[j] = s[j], s[i]
}
func (s ByUID) Less(i, j int) bool {
	maxUID_i := getMaxUID(s[i])
	maxUID_j := getMaxUID(s[j])
	return maxUID_i < maxUID_j
}