internal/ui/tree.go
1
package ui
3
import (
4
"path"
5
"sort"
6
"strings"
8
"github.com/koment-dev/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.StatusAmbiguous: 2,
24
anchor.StatusDrifted: 3,
25
anchor.StatusOrphaned: 4,
26
}
28
func buildTree(files []entry, current string) ([]treeNode, []entry) {
29
root := &treeNode{}
30
for _, file := range files {
31
directory := findOrCreateDirectory(root, path.Dir(file.Path))
32
directory.Files = append(directory.Files, file)
33
}
35
collapse(root)
36
summariseTree(root, current)
37
return root.Dirs, root.Files
38
}
40
func findOrCreateDirectory(root *treeNode, directory string) *treeNode {
41
if directory == "." || directory == "" {
42
return root
43
}
45
at := root
46
for _, segment := range strings.Split(directory, "/") {
47
next := (*treeNode)(nil)
48
for i := range at.Dirs {
49
if at.Dirs[i].Name == segment {
50
next = &at.Dirs[i]
51
break
52
}
53
}
54
if next == nil {
55
at.Dirs = append(at.Dirs, treeNode{Name: segment, Path: path.Join(at.Path, segment)})
56
next = &at.Dirs[len(at.Dirs)-1]
57
}
58
at = next
59
}
60
return at
61
}
63
func collapse(at *treeNode) {
64
for i := range at.Dirs {
65
collapse(&at.Dirs[i])
66
}
68
if at.Path == "" {
69
return
70
}
71
for len(at.Files) == 0 && len(at.Dirs) == 1 {
72
only := at.Dirs[0]
73
at.Name = at.Name + "/" + only.Name
74
at.Path = only.Path
75
at.Files = only.Files
76
at.Dirs = only.Dirs
77
}
78
}
80
func summariseTree(at *treeNode, current string) {
81
sort.Slice(at.Dirs, func(i, j int) bool { return at.Dirs[i].Name < at.Dirs[j].Name })
82
sort.Slice(at.Files, func(i, j int) bool { return at.Files[i].Name < at.Files[j].Name })
84
for _, file := range at.Files {
85
at.Count += file.Count
86
if statusSeverity[file.Worst] > statusSeverity[at.Worst] {
87
at.Worst = file.Worst
88
}
89
if file.Path == current {
90
at.Open = true
91
}
92
}
94
for i := range at.Dirs {
95
child := &at.Dirs[i]
96
summariseTree(child, current)
98
at.Count += child.Count
99
if statusSeverity[child.Worst] > statusSeverity[at.Worst] {
100
at.Worst = child.Worst
101
}
102
if child.Open {
103
at.Open = true
104
}
105
}
106
}