aboutsummaryrefslogtreecommitdiffstats
path: root/app/dirtree.go
diff options
context:
space:
mode:
Diffstat (limited to 'app/dirtree.go')
-rw-r--r--app/dirtree.go213
1 files changed, 95 insertions, 118 deletions
diff --git a/app/dirtree.go b/app/dirtree.go
index a7d0a5e7..dc80fa7f 100644
--- a/app/dirtree.go
+++ b/app/dirtree.go
@@ -3,7 +3,6 @@ package app
import (
"fmt"
"sort"
- "strconv"
"strings"
"time"
@@ -23,8 +22,6 @@ type DirectoryTree struct {
listIdx int
list []*types.Thread
- treeDirs []string
-
virtual bool
virtualCb func()
}
@@ -33,7 +30,6 @@ func NewDirectoryTree(dirlist *DirectoryList) DirectoryLister {
dt := &DirectoryTree{
DirectoryList: dirlist,
listIdx: -1,
- list: make([]*types.Thread, 0),
virtualCb: func() {},
}
return dt
@@ -48,13 +44,12 @@ func (dt *DirectoryTree) Selected() string {
return dt.DirectoryList.Selected()
}
node := dt.list[dt.listIdx]
- sep := dt.DirectoryList.worker.PathSeparator()
- elems := strings.Split(dt.treeDirs[getAnyUid(node)], sep)
+ elems := dt.nodeElems(node)
n := countLevels(node)
if n < 0 || n >= len(elems) {
return ""
}
- return strings.Join(elems[:(n+1)], sep)
+ return strings.Join(elems[:(n+1)], dt.DirectoryList.worker.PathSeparator())
}
func (dt *DirectoryTree) SelectedDirectory() *models.Directory {
@@ -211,27 +206,24 @@ func (dt *DirectoryTree) SelectedMsgStore() (*lib.MessageStore, bool) {
if dt.virtual {
return nil, false
}
- if findString(dt.treeDirs, dt.selected) < 0 {
+
+ selected := models.UID(dt.selected)
+ if _, node := dt.getTreeNode(selected); node == nil {
dt.buildTree()
- if idx := findString(dt.treeDirs, dt.selected); idx >= 0 {
- selIdx, node := dt.getTreeNode(uint32(idx))
- if node != nil {
- makeVisible(node)
- dt.listIdx = selIdx
- }
+ selIdx, node := dt.getTreeNode(selected)
+ if node != nil {
+ makeVisible(node)
+ dt.listIdx = selIdx
}
}
return dt.DirectoryList.SelectedMsgStore()
}
func (dt *DirectoryTree) reindex(name string) {
- idx := findString(dt.treeDirs, name)
- if idx >= 0 {
- selIdx, node := dt.getTreeNode(uint32(idx))
- if node != nil {
- makeVisible(node)
- dt.listIdx = selIdx
- }
+ selIdx, node := dt.getTreeNode(models.UID(name))
+ if node != nil {
+ makeVisible(node)
+ dt.listIdx = selIdx
}
}
@@ -247,7 +239,8 @@ func (dt *DirectoryTree) Open(name string, query string, delay time.Duration, cb
return
}
again := false
- if findString(dt.dirs, name) < 0 {
+ uid := models.UID(name)
+ if _, node := dt.getTreeNode(uid); node == nil {
again = true
} else {
dt.reindex(name)
@@ -300,13 +293,14 @@ func (dt *DirectoryTree) NextPrev(delta int) {
func (dt *DirectoryTree) selectIndex(i int) {
dt.listIdx = i
- if path := dt.getDirectory(dt.list[dt.listIdx]); path != "" {
- dt.virtual = false
- dt.Select(path)
- } else {
+ node := dt.list[dt.listIdx]
+ if node.Dummy {
dt.virtual = true
dt.NewContext()
dt.virtualCb()
+ } else {
+ dt.virtual = false
+ dt.Select(dt.getDirectory(node))
}
}
@@ -345,37 +339,43 @@ func (dt *DirectoryTree) countVisible(list []*types.Thread) (n int) {
return
}
+func (dt *DirectoryTree) nodeElems(node *types.Thread) []string {
+ dir := string(node.Uid)
+ sep := dt.DirectoryList.worker.PathSeparator()
+ return strings.Split(dir, sep)
+}
+
+func (dt *DirectoryTree) nodeName(node *types.Thread) string {
+ if elems := dt.nodeElems(node); len(elems) > 0 {
+ return elems[len(elems)-1]
+ }
+ return ""
+}
+
func (dt *DirectoryTree) displayText(node *types.Thread) string {
- elems := strings.Split(dt.treeDirs[getAnyUid(node)], dt.DirectoryList.worker.PathSeparator())
return fmt.Sprintf("%s%s%s",
threadPrefix(node, false, false),
- getFlag(node), elems[countLevels(node)])
+ getFlag(node), dt.nodeName(node))
}
func (dt *DirectoryTree) getDirectory(node *types.Thread) string {
- if uid := node.Uid; int(uid) < len(dt.treeDirs) {
- return dt.treeDirs[uid]
- }
- return ""
+ return string(node.Uid)
}
-func (dt *DirectoryTree) getTreeNode(uid uint32) (int, *types.Thread) {
- var found *types.Thread
- var idx int
+func (dt *DirectoryTree) getTreeNode(uid models.UID) (int, *types.Thread) {
for i, node := range dt.list {
if node.Uid == uid {
- found = node
- idx = i
+ return i, node
}
}
- return idx, found
+ return -1, nil
}
func (dt *DirectoryTree) hiddenDirectories() map[string]bool {
hidden := make(map[string]bool, 0)
for _, node := range dt.list {
if node.Hidden != 0 && node.FirstChild != nil {
- elems := strings.Split(dt.treeDirs[getAnyUid(node)], dt.DirectoryList.worker.PathSeparator())
+ elems := dt.nodeElems(node)
if levels := countLevels(node); levels < len(elems) {
if node.FirstChild != nil && (levels+1) < len(elems) {
levels += 1
@@ -390,8 +390,9 @@ func (dt *DirectoryTree) hiddenDirectories() map[string]bool {
}
func (dt *DirectoryTree) setHiddenDirectories(hiddenDirs map[string]bool) {
+ log.Tracef("setHiddenDirectories: %#v", hiddenDirs)
for _, node := range dt.list {
- elems := strings.Split(dt.treeDirs[getAnyUid(node)], dt.DirectoryList.worker.PathSeparator())
+ elems := dt.nodeElems(node)
if levels := countLevels(node); levels < len(elems) {
if node.FirstChild != nil && (levels+1) < len(elems) {
levels += 1
@@ -399,6 +400,7 @@ func (dt *DirectoryTree) setHiddenDirectories(hiddenDirs map[string]bool) {
strDir := strings.Join(elems[:levels], dt.DirectoryList.worker.PathSeparator())
if hidden, ok := hiddenDirs[strDir]; hidden && ok {
node.Hidden = 1
+ log.Tracef("setHiddenDirectories: %q -> %#v", strDir, node)
}
}
}
@@ -407,29 +409,15 @@ func (dt *DirectoryTree) setHiddenDirectories(hiddenDirs map[string]bool) {
func (dt *DirectoryTree) buildTree() {
if len(dt.list) != 0 {
hiddenDirs := dt.hiddenDirectories()
- defer func() {
- dt.setHiddenDirectories(hiddenDirs)
- }()
- }
-
- sTree := make([][]string, 0)
- for i, dir := range dt.dirs {
- elems := strings.Split(dir, dt.DirectoryList.worker.PathSeparator())
- if len(elems) == 0 {
- continue
- }
- elems = append(elems, fmt.Sprintf("%d", i))
- sTree = append(sTree, elems)
+ defer dt.setHiddenDirectories(hiddenDirs)
}
- dt.treeDirs = make([]string, len(dt.dirs))
- copy(dt.treeDirs, dt.dirs)
-
- root := &types.Thread{Uid: 0}
- dt.buildTreeNode(root, sTree, 0xFFFFFF, 1)
-
- threads := make([]*types.Thread, 0)
+ dirs := make([]string, len(dt.dirs))
+ copy(dirs, dt.dirs)
+ root := &types.Thread{}
+ dt.buildTreeNode(root, dirs, 1)
+ var threads []*types.Thread
for iter := root.FirstChild; iter != nil; iter = iter.NextSibling {
iter.Parent = nil
threads = append(threads, iter)
@@ -437,16 +425,10 @@ func (dt *DirectoryTree) buildTree() {
// folders-sort
if dt.DirectoryList.acctConf.EnableFoldersSort {
- toStr := func(t *types.Thread) string {
- if elems := strings.Split(dt.treeDirs[getAnyUid(t)], dt.DirectoryList.worker.PathSeparator()); len(elems) > 0 {
- return elems[0]
- }
- return ""
- }
sort.Slice(threads, func(i, j int) bool {
foldersSort := dt.DirectoryList.acctConf.FoldersSort
- iInFoldersSort := findString(foldersSort, toStr(threads[i]))
- jInFoldersSort := findString(foldersSort, toStr(threads[j]))
+ iInFoldersSort := findString(foldersSort, dt.getDirectory(threads[i]))
+ jInFoldersSort := findString(foldersSort, dt.getDirectory(threads[j]))
if iInFoldersSort >= 0 && jInFoldersSort >= 0 {
return iInFoldersSort < jInFoldersSort
}
@@ -456,7 +438,7 @@ func (dt *DirectoryTree) buildTree() {
if jInFoldersSort >= 0 {
return false
}
- return toStr(threads[i]) < toStr(threads[j])
+ return dt.getDirectory(threads[i]) < dt.getDirectory(threads[j])
})
}
@@ -472,41 +454,51 @@ func (dt *DirectoryTree) buildTree() {
}
}
-func (dt *DirectoryTree) buildTreeNode(node *types.Thread, stree [][]string, defaultUid uint32, depth int) {
- m := make(map[string][][]string)
- for _, branch := range stree {
- if len(branch) > 1 {
- next := append(m[branch[0]], branch[1:]) //nolint:gocritic // intentional append to different slice
- m[branch[0]] = next
- }
- }
- keys := make([]string, 0)
- for key := range m {
- keys = append(keys, key)
- }
- sort.Strings(keys)
- path := dt.getDirectory(node)
- for _, key := range keys {
- next := m[key]
- var uid uint32 = defaultUid
- for _, testStr := range next {
- if len(testStr) == 1 {
- if uidI, err := strconv.Atoi(next[0][0]); err == nil {
- uid = uint32(uidI)
- }
+func (dt *DirectoryTree) buildTreeNode(node *types.Thread, dirs []string, depth int) {
+ dirmap := make(map[string][]string)
+ for _, dir := range dirs {
+ base, dir, cut := strings.Cut(
+ dir, dt.DirectoryList.worker.PathSeparator())
+ if _, found := dirmap[base]; found {
+ if cut {
+ dirmap[base] = append(dirmap[base], dir)
}
+ } else if cut {
+ dirmap[base] = append(dirmap[base], dir)
+ } else {
+ dirmap[base] = []string{}
}
- nextNode := &types.Thread{Uid: uid}
+ }
+ bases := make([]string, 0, len(dirmap))
+ for base, dirs := range dirmap {
+ bases = append(bases, base)
+ sort.Strings(dirs)
+ }
+ sort.Strings(bases)
+
+ basePath := dt.getDirectory(node)
+ if depth > dt.UiConfig(basePath).DirListCollapse {
+ node.Hidden = 1
+ } else {
+ node.Hidden = 0
+ }
+
+ for _, base := range bases {
+ path := dt.childPath(basePath, base)
+ nextNode := &types.Thread{Uid: models.UID(path)}
+
+ nextNode.Dummy = findString(dt.dirs, path) == -1
+
node.AddChild(nextNode)
- if dt.UiConfig(path).DirListCollapse != 0 && dt.listIdx < 0 {
- if depth > dt.UiConfig(path).DirListCollapse {
- node.Hidden = 1
- } else {
- node.Hidden = 0
- }
- }
- dt.buildTreeNode(nextNode, next, defaultUid, depth+1)
+ dt.buildTreeNode(nextNode, dirmap[base], depth+1)
+ }
+}
+
+func (dt *DirectoryTree) childPath(base, relpath string) string {
+ if base == "" {
+ return relpath
}
+ return base + dt.DirectoryList.worker.PathSeparator() + relpath
}
func makeVisible(node *types.Thread) {
@@ -519,27 +511,12 @@ func makeVisible(node *types.Thread) {
}
func isVisible(node *types.Thread) bool {
- isVisible := true
for iter := node.Parent; iter != nil; iter = iter.Parent {
if iter.Hidden != 0 {
- isVisible = false
- break
+ return false
}
}
- return isVisible
-}
-
-func getAnyUid(node *types.Thread) (uid uint32) {
- err := node.Walk(func(t *types.Thread, l int, err error) error {
- if t.FirstChild == nil {
- uid = t.Uid
- }
- return nil
- })
- if err != nil {
- log.Warnf("failed to get uid: %v", err)
- }
- return
+ return true
}
func countLevels(node *types.Thread) (level int) {
@@ -550,7 +527,7 @@ func countLevels(node *types.Thread) (level int) {
}
func getFlag(node *types.Thread) string {
- if node == nil && node.FirstChild == nil {
+ if node == nil || node.FirstChild == nil {
return ""
}
if node.Hidden != 0 {