internal/ui/tree.go
1
package ui
3
import (
4
"path"
5
"sort"
6
"strings"
8
"github.com/janpuc/koment/internal/anchor"
9
)
11
type treeNode struct {
12
Name string
13
Path string
14
Dirs []treeNode
15
Files []entry
16
Count int
17
Worst anchor.Status
18
Open bool
19
}
21
var statusSeverity = map[anchor.Status]int{
22
anchor.StatusOK: 0,
23
anchor.StatusMoved: 1,
24
anchor.StatusAmbiguous: 2,
25
anchor.StatusDrifted: 3,
26
anchor.StatusOrphaned: 4,
27
}
29
func buildTree(files []entry, current string) ([]treeNode, []entry) {
30
root := &treeNode{}
31
for _, file := range files {
32
directory := findOrCreateDirectory(root, path.Dir(file.Path))
33
directory.Files = append(directory.Files, file)
34
}
36
collapse(root)
37
summariseTree(root, current)
38
return root.Dirs, root.Files
39
}
41
func findOrCreateDirectory(root *treeNode, directory string) *treeNode {
42
if directory == "." || directory == "" {
43
return root
44
}
46
at := root
47
for _, segment := range strings.Split(directory, "/") {
48
next := (*treeNode)(nil)
49
for i := range at.Dirs {
50
if at.Dirs[i].Name == segment {
51
next = &at.Dirs[i]
52
break
53
}
54
}
55
if next == nil {
56
at.Dirs = append(at.Dirs, treeNode{Name: segment, Path: path.Join(at.Path, segment)})
57
next = &at.Dirs[len(at.Dirs)-1]
58
}
59
at = next
60
}
61
return at
62
}
64
func collapse(at *treeNode) {
65
for i := range at.Dirs {
66
collapse(&at.Dirs[i])
67
}
69
if at.Path == "" {
70
return
71
}
72
for len(at.Files) == 0 && len(at.Dirs) == 1 {
73
only := at.Dirs[0]
74
at.Name = at.Name + "/" + only.Name
75
at.Path = only.Path
76
at.Files = only.Files
77
at.Dirs = only.Dirs
78
}
79
}
81
func summariseTree(at *treeNode, current string) {
82
sort.Slice(at.Dirs, func(i, j int) bool { return at.Dirs[i].Name < at.Dirs[j].Name })
83
sort.Slice(at.Files, func(i, j int) bool { return at.Files[i].Name < at.Files[j].Name })
85
for _, file := range at.Files {
86
at.Count += file.Count
87
if statusSeverity[file.Worst] > statusSeverity[at.Worst] {
88
at.Worst = file.Worst
89
}
90
if file.Path == current {
91
at.Open = true
92
}
93
}
95
for i := range at.Dirs {
96
child := &at.Dirs[i]
97
summariseTree(child, current)
99
at.Count += child.Count
100
if statusSeverity[child.Worst] > statusSeverity[at.Worst] {
101
at.Worst = child.Worst
102
}
103
if child.Open {
104
at.Open = true
105
}
106
}
107
}