2018-11-09 17:25:50 +00:00
|
|
|
package tree
|
2018-05-27 15:36:03 +00:00
|
|
|
|
2018-10-25 16:09:03 +00:00
|
|
|
import (
|
|
|
|
"fmt"
|
2020-08-12 18:13:01 +00:00
|
|
|
|
2020-11-06 17:50:36 +00:00
|
|
|
"git.sp4ke.xyz/sp4ke/gomark/bookmarks"
|
|
|
|
"git.sp4ke.xyz/sp4ke/gomark/index"
|
|
|
|
"git.sp4ke.xyz/sp4ke/gomark/logging"
|
2022-12-15 02:22:54 +00:00
|
|
|
"git.sp4ke.xyz/sp4ke/gomark/utils"
|
2022-12-11 22:06:07 +00:00
|
|
|
"github.com/kr/pretty"
|
2018-10-25 16:09:03 +00:00
|
|
|
|
|
|
|
"github.com/xlab/treeprint"
|
|
|
|
)
|
|
|
|
|
2022-10-07 20:15:48 +00:00
|
|
|
var log = logging.GetLogger("TREE")
|
2018-11-09 17:25:50 +00:00
|
|
|
|
|
|
|
type Bookmark = bookmarks.Bookmark
|
|
|
|
|
2022-10-27 22:33:20 +00:00
|
|
|
type NodeType int
|
|
|
|
|
|
|
|
const (
|
2022-11-07 19:07:13 +00:00
|
|
|
RootNode NodeType = iota
|
2022-10-27 22:33:20 +00:00
|
|
|
URLNode
|
|
|
|
FolderNode
|
|
|
|
TagNode
|
|
|
|
)
|
|
|
|
|
2018-06-08 15:38:57 +00:00
|
|
|
type Node struct {
|
|
|
|
Name string
|
2022-10-27 22:33:20 +00:00
|
|
|
Type NodeType // folder, tag, url
|
2018-06-08 15:38:57 +00:00
|
|
|
URL string
|
|
|
|
Tags []string
|
|
|
|
Desc string
|
|
|
|
HasChanged bool
|
|
|
|
NameHash uint64 // hash of the metadata
|
|
|
|
Parent *Node
|
|
|
|
Children []*Node
|
|
|
|
}
|
|
|
|
|
2018-10-25 16:09:03 +00:00
|
|
|
func (node *Node) GetRoot() *Node {
|
|
|
|
nodePtr := node
|
|
|
|
|
2022-09-28 20:07:03 +00:00
|
|
|
for nodePtr.Name != "root" {
|
2018-10-25 16:09:03 +00:00
|
|
|
nodePtr = nodePtr.Parent
|
|
|
|
}
|
|
|
|
|
|
|
|
return nodePtr
|
|
|
|
}
|
|
|
|
|
2022-12-10 01:49:04 +00:00
|
|
|
// Returns the ancestor of this node
|
|
|
|
func Ancestor(node *Node) *Node {
|
|
|
|
if node.Parent == nil {
|
|
|
|
return node
|
|
|
|
} else {
|
|
|
|
return Ancestor(node.Parent)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-11 22:06:07 +00:00
|
|
|
func (node *Node) DirectChildOf(parent *Node) bool {
|
2022-12-26 18:15:00 +00:00
|
|
|
if len(parent.Children) == 0 { return false }
|
|
|
|
var found bool
|
|
|
|
for _, child := range parent.Children {
|
|
|
|
if node == child { found = true }
|
|
|
|
}
|
|
|
|
|
|
|
|
return found
|
2022-12-11 22:06:07 +00:00
|
|
|
}
|
2022-12-10 01:49:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
// Finds a node and the tree starting at root
|
|
|
|
func FindNode(node *Node, root *Node) bool {
|
|
|
|
|
|
|
|
if node == root {
|
|
|
|
return true
|
|
|
|
} else {
|
|
|
|
for _, child := range root.Children {
|
|
|
|
found := FindNode(node, child)
|
|
|
|
if found { return true }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2022-12-11 22:06:07 +00:00
|
|
|
func FindNodeByName(name string, root *Node) bool {
|
|
|
|
|
|
|
|
if name == root.Name {
|
|
|
|
return true
|
|
|
|
} else {
|
|
|
|
for _, child := range root.Children {
|
|
|
|
found := FindNodeByName(name, child)
|
|
|
|
if found { return true }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
2022-12-15 02:22:54 +00:00
|
|
|
|
|
|
|
// Inserts child node into parent node. Parent will point to child
|
|
|
|
// and child will point to parent EXCEPT when parent is a TAG node.
|
|
|
|
// If parent is a Tag node, child should not point back to parent
|
|
|
|
// as URL nodes should always point to folder parent nodes only.
|
2022-10-07 20:15:48 +00:00
|
|
|
func AddChild(parent *Node, child *Node) {
|
2022-11-07 19:07:13 +00:00
|
|
|
log.Debugf("adding child %v: <%s>", child.Type, child.Name)
|
2022-10-07 20:15:48 +00:00
|
|
|
|
2022-12-15 02:22:54 +00:00
|
|
|
|
2022-10-07 20:15:48 +00:00
|
|
|
if len(parent.Children) == 0 {
|
|
|
|
parent.Children = []*Node{child}
|
2022-12-15 02:22:54 +00:00
|
|
|
|
|
|
|
// Do not point back to TAG parent node from child
|
|
|
|
if parent.Type != TagNode {
|
|
|
|
child.Parent = parent
|
|
|
|
}
|
2022-10-07 20:15:48 +00:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, n := range parent.Children {
|
|
|
|
if child == n {
|
2022-12-11 22:06:07 +00:00
|
|
|
// log.Errorf("<%s> Node already exists", child)
|
2022-12-15 02:22:54 +00:00
|
|
|
log.Info(pretty.Sprintf("skipping node <%s>, already exists", child.Name))
|
2022-10-07 20:15:48 +00:00
|
|
|
return
|
2018-11-13 16:11:16 +00:00
|
|
|
}
|
|
|
|
}
|
2022-10-07 20:15:48 +00:00
|
|
|
|
|
|
|
parent.Children = append(parent.Children, child)
|
2022-12-15 02:22:54 +00:00
|
|
|
if parent.Type != TagNode {
|
|
|
|
child.Parent = parent
|
|
|
|
}
|
2018-11-13 16:11:16 +00:00
|
|
|
}
|
|
|
|
|
2018-10-25 16:09:03 +00:00
|
|
|
func PrintTree(root *Node) {
|
2022-12-10 01:49:04 +00:00
|
|
|
fmt.Println("---")
|
|
|
|
fmt.Println("PrintTree")
|
2018-10-25 16:09:03 +00:00
|
|
|
var walk func(node *Node, tree treeprint.Tree)
|
|
|
|
tree := treeprint.New()
|
|
|
|
|
|
|
|
walk = func(node *Node, t treeprint.Tree) {
|
|
|
|
|
|
|
|
if len(node.Children) > 0 {
|
2022-12-10 01:49:04 +00:00
|
|
|
t = t.AddBranch(fmt.Sprintf("%#v <%s>", node.Type, node.Name))
|
2018-10-25 16:09:03 +00:00
|
|
|
|
|
|
|
for _, child := range node.Children {
|
2022-12-10 01:49:04 +00:00
|
|
|
walk(child, t)
|
2018-10-25 16:09:03 +00:00
|
|
|
}
|
|
|
|
} else {
|
2022-12-10 01:49:04 +00:00
|
|
|
t.AddNode(fmt.Sprintf("%#v <%s>", node.Type, node.Name))
|
2018-10-25 16:09:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
walk(root, tree)
|
2018-11-09 17:25:50 +00:00
|
|
|
fmt.Println(tree.String())
|
2022-12-10 01:49:04 +00:00
|
|
|
fmt.Println("---")
|
2018-10-25 16:09:03 +00:00
|
|
|
}
|
|
|
|
|
2018-05-27 15:36:03 +00:00
|
|
|
// Rebuilds the memory url index after parsing all bookmarks.
|
|
|
|
// Keeps memory index in sync with last known state of browser bookmarks
|
2018-11-09 17:25:50 +00:00
|
|
|
func WalkBuildIndex(node *Node, index index.HashTree) {
|
2022-10-27 22:33:20 +00:00
|
|
|
if node.Type == URLNode {
|
2018-11-09 17:25:50 +00:00
|
|
|
index.Insert(node.URL, node)
|
2018-05-27 15:36:03 +00:00
|
|
|
//log.Debugf("Inserted URL: %s and Hash: %v", node.URL, node.NameHash)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(node.Children) > 0 {
|
|
|
|
for _, node := range node.Children {
|
2019-03-01 18:14:12 +00:00
|
|
|
WalkBuildIndex(node, index)
|
2018-05-27 15:36:03 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-26 19:55:48 +00:00
|
|
|
// Get all possible tags for this url node
|
|
|
|
// The tags make sense only in the context of a URL node
|
|
|
|
// This will traverse the three breadth first to find all Parent folders and
|
|
|
|
// add them as a tag. URL nodes should already be populated with the list of
|
|
|
|
// tags that exist under the TAG tree. So we only need to find the parent folders
|
|
|
|
// and turn them into tags.
|
2022-12-15 02:22:54 +00:00
|
|
|
func (node *Node) getTags() []string {
|
|
|
|
|
2022-12-26 19:55:48 +00:00
|
|
|
if node.Parent.Type == RootNode {
|
|
|
|
return []string{}
|
2022-12-15 02:22:54 +00:00
|
|
|
}
|
|
|
|
|
2022-12-26 19:55:48 +00:00
|
|
|
if node.Parent.Type == FolderNode {
|
2022-12-26 20:08:30 +00:00
|
|
|
// clean out the Tag separator from folder names
|
2022-12-26 19:55:48 +00:00
|
|
|
node.Tags = utils.Extends(node.Tags, node.Parent.Name)
|
|
|
|
return append(node.Parent.getTags(), node.Tags...)
|
2022-12-15 02:22:54 +00:00
|
|
|
}
|
|
|
|
|
2022-12-26 19:55:48 +00:00
|
|
|
return node.Tags
|
2022-12-15 02:22:54 +00:00
|
|
|
}
|
|
|
|
|
2018-11-09 17:25:50 +00:00
|
|
|
func (node *Node) GetBookmark() *Bookmark {
|
2022-12-26 19:55:48 +00:00
|
|
|
|
|
|
|
if node.Type != URLNode {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-11-09 17:25:50 +00:00
|
|
|
return &Bookmark{
|
|
|
|
URL: node.URL,
|
|
|
|
Metadata: node.Name,
|
|
|
|
Desc: node.Desc,
|
2022-12-15 02:22:54 +00:00
|
|
|
Tags: node.getTags(),
|
2018-05-27 15:36:03 +00:00
|
|
|
}
|
|
|
|
}
|