dont traverse the tree root node
This commit is contained in:
parent
598d95f5f7
commit
fd397ac932
@ -5,6 +5,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/fatih/color"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type FileNode struct {
|
||||
@ -30,10 +31,12 @@ func NewNode(parent *FileNode, name string, data *FileInfo) (node *FileNode) {
|
||||
return node
|
||||
}
|
||||
|
||||
func (node *FileNode) Copy() *FileNode {
|
||||
newNode := NewNode(node.Parent, node.Name, node.Data.FileInfo)
|
||||
func (node *FileNode) Copy(parent *FileNode) *FileNode {
|
||||
newNode := NewNode(parent, node.Name, node.Data.FileInfo)
|
||||
newNode.Data.ViewInfo = node.Data.ViewInfo
|
||||
newNode.Data.DiffType = node.Data.DiffType
|
||||
for name, child := range node.Children {
|
||||
newNode.Children[name] = child.Copy()
|
||||
newNode.Children[name] = child.Copy(newNode)
|
||||
child.Parent = newNode
|
||||
}
|
||||
return newNode
|
||||
@ -52,6 +55,9 @@ func (node *FileNode) AddChild(name string, data *FileInfo) (child *FileNode) {
|
||||
}
|
||||
|
||||
func (node *FileNode) Remove() error {
|
||||
if node == node.Tree.Root {
|
||||
return fmt.Errorf("cannot remove the tree root")
|
||||
}
|
||||
for _, child := range node.Children {
|
||||
child.Remove()
|
||||
}
|
||||
@ -87,25 +93,38 @@ func (node *FileNode) VisitDepthChildFirst(visiter Visiter, evaluator VisitEvalu
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, name := range keys {
|
||||
if evaluator != nil {
|
||||
if !evaluator(node) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
child := node.Children[name]
|
||||
err := child.VisitDepthChildFirst(visiter, evaluator)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// never visit the root node
|
||||
if node == node.Tree.Root {
|
||||
return nil
|
||||
} else if evaluator != nil && evaluator(node) || evaluator == nil {
|
||||
return visiter(node)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (node *FileNode) VisitDepthParentFirst(visiter Visiter, evaluator VisitEvaluator) error {
|
||||
err := visiter(node)
|
||||
var err error
|
||||
|
||||
doVisit := evaluator != nil && evaluator(node) || evaluator == nil
|
||||
|
||||
if !doVisit {
|
||||
return nil
|
||||
}
|
||||
|
||||
// never visit the root node
|
||||
if node != node.Tree.Root{
|
||||
err = visiter(node)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
var keys []string
|
||||
for key := range node.Children {
|
||||
@ -113,11 +132,6 @@ func (node *FileNode) VisitDepthParentFirst(visiter Visiter, evaluator VisitEval
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, name := range keys {
|
||||
if evaluator != nil {
|
||||
if !evaluator(node) {
|
||||
continue
|
||||
}
|
||||
}
|
||||
child := node.Children[name]
|
||||
err = child.VisitDepthParentFirst(visiter, evaluator)
|
||||
if err != nil {
|
||||
|
@ -1,7 +1,6 @@
|
||||
package filetree
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
@ -88,8 +87,10 @@ func (tree *FileTree) String() string {
|
||||
|
||||
func (tree *FileTree) Copy() *FileTree {
|
||||
newTree := NewFileTree()
|
||||
*newTree = *tree
|
||||
newTree.Root = tree.Root.Copy()
|
||||
newTree.Size = tree.Size
|
||||
newTree.Root = tree.Root.Copy(newTree.Root)
|
||||
|
||||
// update the tree pointers
|
||||
newTree.VisitDepthChildFirst(func(node *FileNode) error {
|
||||
node.Tree = newTree
|
||||
return nil
|
||||
@ -116,12 +117,12 @@ func (tree *FileTree) Stack(upper *FileTree) error {
|
||||
if node.IsWhiteout() {
|
||||
err := tree.RemovePath(node.Path())
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot remove node %s: %v", node.Path(), err.Error())
|
||||
return fmt.Errorf("cannot remove node %s: %v", node.Path(), err.Error())
|
||||
}
|
||||
} else {
|
||||
newNode, err := tree.AddPath(node.Path(), node.Data.FileInfo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot add node %s: %v", newNode.Path(), err.Error())
|
||||
return fmt.Errorf("cannot add node %s: %v", newNode.Path(), err.Error())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@ -137,7 +138,7 @@ func (tree *FileTree) GetNode(path string) (*FileNode, error) {
|
||||
continue
|
||||
}
|
||||
if node.Children[name] == nil {
|
||||
return nil, errors.New("Path does not exist")
|
||||
return nil, fmt.Errorf("path does not exist: %s", path)
|
||||
}
|
||||
node = node.Children[name]
|
||||
}
|
||||
@ -183,7 +184,7 @@ func (tree *FileTree) Compare(upper *FileTree) error {
|
||||
if upperNode.IsWhiteout() {
|
||||
err := tree.MarkRemoved(upperNode.Path())
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot remove upperNode %s: %v", upperNode.Path(), err.Error())
|
||||
return fmt.Errorf("cannot remove upperNode %s: %v", upperNode.Path(), err.Error())
|
||||
}
|
||||
} else {
|
||||
lowerNode, _ := tree.GetNode(upperNode.Path())
|
||||
@ -191,7 +192,7 @@ func (tree *FileTree) Compare(upper *FileTree) error {
|
||||
newNode, err := tree.AddPath(upperNode.Path(), upperNode.Data.FileInfo)
|
||||
// fmt.Printf("added new upperNode at %s\n", newNode.Path())
|
||||
if err != nil {
|
||||
return fmt.Errorf("Cannot add new upperNode %s: %v", upperNode.Path(), err.Error())
|
||||
return fmt.Errorf("cannot add new upperNode %s: %v", upperNode.Path(), err.Error())
|
||||
}
|
||||
newNode.AssignDiffType(Added)
|
||||
} else {
|
||||
|
@ -432,3 +432,41 @@ func TestStackRange(t *testing.T) {
|
||||
trees := []*FileTree{lowerTree, upperTree, tree}
|
||||
StackRange(trees, 2)
|
||||
}
|
||||
|
||||
|
||||
func TestRemoveOnIterate(t *testing.T) {
|
||||
|
||||
tree := NewFileTree()
|
||||
paths := [...]string{"/etc", "/usr", "/etc/hosts", "/etc/sudoers", "/usr/bin", "/usr/something"}
|
||||
|
||||
for _, value := range paths {
|
||||
fakeData := FileInfo{
|
||||
Path: value,
|
||||
Typeflag: 1,
|
||||
MD5sum: [16]byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||
}
|
||||
node, err := tree.AddPath(value, &fakeData)
|
||||
if err == nil && stringInSlice(node.Path(), []string{"/etc"}) {
|
||||
node.Data.ViewInfo.Hidden = true
|
||||
}
|
||||
}
|
||||
|
||||
tree.VisitDepthChildFirst(func(node *FileNode) error {
|
||||
if node.Data.ViewInfo.Hidden {
|
||||
tree.RemovePath(node.Path())
|
||||
}
|
||||
return nil
|
||||
}, nil)
|
||||
|
||||
expected := `.
|
||||
└── usr
|
||||
├── bin
|
||||
└── something
|
||||
`
|
||||
actual := tree.String()
|
||||
if expected != actual {
|
||||
t.Errorf("Expected tree string:\n--->%s<---\nGot:\n--->%s<---", expected, actual)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,8 @@ type FileTreeView struct {
|
||||
gui *gocui.Gui
|
||||
view *gocui.View
|
||||
TreeIndex int
|
||||
Tree *filetree.FileTree
|
||||
ModelTree *filetree.FileTree
|
||||
ViewTree *filetree.FileTree
|
||||
RefTrees []*filetree.FileTree
|
||||
HiddenDiffTypes []bool
|
||||
}
|
||||
@ -24,7 +25,7 @@ func NewFileTreeView(name string, gui *gocui.Gui, tree *filetree.FileTree, refTr
|
||||
// populate main fields
|
||||
treeview.Name = name
|
||||
treeview.gui = gui
|
||||
treeview.Tree = tree
|
||||
treeview.ModelTree = tree
|
||||
treeview.RefTrees = refTrees
|
||||
treeview.HiddenDiffTypes = make([]bool, 4)
|
||||
|
||||
@ -65,6 +66,7 @@ func (view *FileTreeView) Setup(v *gocui.View) error {
|
||||
return err
|
||||
}
|
||||
|
||||
view.updateViewTree()
|
||||
view.Render()
|
||||
|
||||
return nil
|
||||
@ -81,14 +83,11 @@ func (view *FileTreeView) setLayer(layerIndex int) error {
|
||||
visitor := func(node *filetree.FileNode) error {
|
||||
newNode, err := newTree.GetNode(node.Path())
|
||||
if err == nil {
|
||||
newNode.Data.ViewInfo.Collapsed = node.Data.ViewInfo.Collapsed
|
||||
newNode.Data.ViewInfo = node.Data.ViewInfo
|
||||
}
|
||||
return nil
|
||||
}
|
||||
view.Tree.VisitDepthChildFirst(visitor, nil)
|
||||
|
||||
// now that the tree has been rebuilt, keep the view seleciton in parity with the previous selection
|
||||
view.setHiddenFromDiffTypes()
|
||||
view.ModelTree.VisitDepthChildFirst(visitor, nil)
|
||||
|
||||
if debug {
|
||||
v, _ := view.gui.View("debug")
|
||||
@ -96,9 +95,11 @@ func (view *FileTreeView) setLayer(layerIndex int) error {
|
||||
_, _ = fmt.Fprintln(v, view.RefTrees[layerIndex])
|
||||
}
|
||||
|
||||
|
||||
view.view.SetCursor(0, 0)
|
||||
view.TreeIndex = 0
|
||||
view.Tree = newTree
|
||||
view.ModelTree = newTree
|
||||
view.updateViewTree()
|
||||
return view.Render()
|
||||
}
|
||||
|
||||
@ -115,6 +116,8 @@ func (view *FileTreeView) CursorUp() error {
|
||||
if err == nil {
|
||||
view.TreeIndex--
|
||||
}
|
||||
// tmp tmp tmp
|
||||
view.getAbsPositionNode()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -123,21 +126,26 @@ func (view *FileTreeView) getAbsPositionNode() (node *filetree.FileNode) {
|
||||
var evaluator func(*filetree.FileNode) bool
|
||||
var dfsCounter int
|
||||
|
||||
// special case: the root node is never visited
|
||||
if view.TreeIndex == 0 {
|
||||
return view.ModelTree.Root
|
||||
}
|
||||
|
||||
visiter = func(curNode *filetree.FileNode) error {
|
||||
dfsCounter++
|
||||
if dfsCounter == view.TreeIndex {
|
||||
node = curNode
|
||||
}
|
||||
dfsCounter++
|
||||
return nil
|
||||
}
|
||||
|
||||
evaluator = func(curNode *filetree.FileNode) bool {
|
||||
return !curNode.Data.ViewInfo.Collapsed && !curNode.Data.ViewInfo.Hidden
|
||||
return !curNode.Parent.Data.ViewInfo.Collapsed && !curNode.Data.ViewInfo.Hidden
|
||||
}
|
||||
|
||||
err := view.Tree.VisitDepthParentFirst(visiter, evaluator)
|
||||
err := view.ModelTree.VisitDepthParentFirst(visiter, evaluator)
|
||||
if err != nil {
|
||||
// todo: you guessed it, check errors
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return node
|
||||
@ -146,25 +154,39 @@ func (view *FileTreeView) getAbsPositionNode() (node *filetree.FileNode) {
|
||||
func (view *FileTreeView) toggleCollapse() error {
|
||||
node := view.getAbsPositionNode()
|
||||
node.Data.ViewInfo.Collapsed = !node.Data.ViewInfo.Collapsed
|
||||
return view.Render()
|
||||
}
|
||||
|
||||
func (view *FileTreeView) setHiddenFromDiffTypes() error {
|
||||
visitor := func(node *filetree.FileNode) error {
|
||||
node.Data.ViewInfo.Hidden = view.HiddenDiffTypes[node.Data.DiffType]
|
||||
return nil
|
||||
}
|
||||
view.Tree.VisitDepthChildFirst(visitor, nil)
|
||||
view.updateViewTree()
|
||||
return view.Render()
|
||||
}
|
||||
|
||||
func (view *FileTreeView) toggleShowDiffType(diffType filetree.DiffType) error {
|
||||
view.HiddenDiffTypes[diffType] = !view.HiddenDiffTypes[diffType]
|
||||
return view.setHiddenFromDiffTypes()
|
||||
|
||||
view.view.SetCursor(0, 0)
|
||||
view.TreeIndex = 0
|
||||
view.updateViewTree()
|
||||
return view.Render()
|
||||
}
|
||||
|
||||
func (view *FileTreeView) updateViewTree() {
|
||||
// keep the view selection in parity with the current DiffType selection
|
||||
view.ModelTree.VisitDepthChildFirst(func(node *filetree.FileNode) error {
|
||||
node.Data.ViewInfo.Hidden = view.HiddenDiffTypes[node.Data.DiffType]
|
||||
return nil
|
||||
}, nil)
|
||||
|
||||
// make a new tree with only visible nodes
|
||||
view.ViewTree = view.ModelTree.Copy()
|
||||
view.ViewTree.VisitDepthParentFirst(func(node *filetree.FileNode) error {
|
||||
if node.Data.ViewInfo.Hidden {
|
||||
view.ViewTree.RemovePath(node.Path())
|
||||
}
|
||||
return nil
|
||||
}, nil)
|
||||
}
|
||||
|
||||
func (view *FileTreeView) Render() error {
|
||||
renderString := view.Tree.String()
|
||||
// print the tree to the view
|
||||
renderString := view.ViewTree.String()
|
||||
view.gui.Update(func(g *gocui.Gui) error {
|
||||
view.view.Clear()
|
||||
_, err := fmt.Fprintln(view.view, renderString)
|
||||
|
Loading…
x
Reference in New Issue
Block a user