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