treeprint

repository·master·Indexed 19 days ago

https://github.com/xlab/treeprint

A Go package for composing and rendering ASCII trees, mimicking the visual style of the tree command-line utility. It provides a fluent API to build structures using AddNode and AddBranch, supports metadata attachment via AddMetaNode and AddMetaBranch, and includes utilities to generate tree representations from Go structs using FromStruct and FromStructWithMeta. The library supports custom struct tags for field visibility and provides methods for tree traversal and searching.

Tokens
3.3K
Snippets
14
Records
16
Agent score
63%

What's inside treeprint

  1. How treeprint works

    master

    The treeprint package allows you to build and render ASCII trees using a fluent API.

    1. Initialize: Create a new tree using treeprint.New() (or treeprint.NewWithRoot(name) for a custom root).
    2. Build Structure:
      • Use AddNode(name) to add a node at the current level.
      • Use AddBranch(name) to create a new level (a branch) and descend into it.
    3. Render: Call .String() or .Bytes() on the root tree or a specific branch to get the ASCII representation of that subtree.
    tree := treeprint.New()
    // Add a branch and descend
    branch := tree.AddBranch("folder")
    // Add nodes inside that branch
    branch.AddNode("file1").AddNode("file2")
    // Print the whole tree
    fmt.Println(tree.String())
  2. Configure struct field visibility with `tree` tags

    master

    You can control how treeprint processes struct fields using the tree struct tag. This affects FromStruct and FromStructWithMeta calls.

    Supported tag behaviors:

    • tree:"-": Skips the field entirely.
    • tree:"new_name": Uses new_name as the node name instead of the actual field name.
    • tree:"name,omitempty": Omits the field if it is considered empty (zero value).
    type User struct {
        ID       int    `tree:"user_id"`       // Renames field in tree
        Password string `tree:"-"`             // Skips field
        Email    string `tree:"email,omitempty"` // Omits if empty
    }
  3. How the Tree API works

    master

    The treeprint library uses a hierarchical Node structure to build ASCII trees.

    • Nodes vs Branches: A Node is a simple container for a Value and optional Meta. A Node becomes a branch when it contains child nodes. You can explicitly turn a leaf into a branch using the Branch() method.
    • Metadata: Every node can carry a MetaValue. This is useful for attaching context (like file permissions, IDs, or status) to a node without polluting the primary Value.
    • Traversal: The library supports searching (FindByValue, FindByMeta) and full traversal (VisitAll). VisitAll uses a breadth-first approach.
    • Rendering: The rendering engine handles multi-line values by automatically calculating the necessary padding and link edges (, ├──, └──) to maintain visual alignment.
  4. Render a complex data structure

    master

    You can build deeply nested structures by chaining AddBranch and AddNode calls. AddBranch moves the context one level deeper, while AddNode keeps the context at the current level.

    func main() {
        // to add a custom root name use `treeprint.NewWithRoot()` instead
        tree := treeprint.New()
    
        // create a new branch in the root
        one := tree.AddBranch("one")
    
        // add some nodes
        one.AddNode("subnode1").AddNode("subnode2")
    
        // create a new sub-branch
        one.AddBranch("two").
            AddNode("subnode1").AddNode("subnode2"). // add some nodes
            AddBranch("three"). // add a new sub-branch
            AddNode("subnode1").AddNode("subnode2") // add some nodes too
    
        // add one more node that should surround the inner branch
        one.AddNode("subnode3")
    
        // add a new node to the root
        tree.AddNode("outernode")
    
        fmt.Println(tree.String())
    }
  5. Create a tree with metadata

    master

    If you need to attach metadata (like file sizes or permissions) to nodes or branches, use the following methods:

    • AddMetaBranch(meta, name): Creates a branch that includes metadata in brackets, e.g., [ 204] bin.
    • AddMetaNode(meta, name): Adds a leaf node with metadata, e.g., [122K] testtool.a.
    func main() {
        // to add a custom root name use `treeprint.NewWithRoot()` instead
        tree := treeprint.New()
    
        tree.AddNode("Dockerfile")
        tree.AddNode("Makefile")
        tree.AddNode("aws.sh")
        tree.AddMetaBranch(" 204", "bin").
            AddNode("dbmaker").AddNode("someserver").AddNode("testtool")
        tree.AddMetaBranch(" 374", "deploy").
            AddNode("Makefile").AddNode("bootstrap.sh")
        tree.AddMetaNode("122K", "testtool.a")
    
        fmt.Println(tree.String())
    }
  6. Iterate over tree nodes with VisitAll

    master

    To traverse the entire tree, call VisitAll on the root node. This method accepts a callback function that is executed for every node in the tree. Inside the callback, you can distinguish between branch nodes and leaf nodes by checking the length of the Nodes slice on the *node object.

    tree := treeprint.New()
    
    one := tree.AddBranch("one")
    one.AddNode("one-subnode1").AddNode("one-subnode2")
    one.AddBranch("two").AddNode("two-subnode1").AddNode("two-subnode2").
        AddBranch("three").AddNode("three-subnode1").AddNode("three-subnode2")
    tree.AddNode("outernode")
    
    // if you need to iterate over the whole tree
    // call `VisitAll` from your top root node.
    tree.VisitAll(func(item *node) {
        if len(item.Nodes) > 0 {
            // branch nodes
            fmt.Println(item.Value) // will output one, two, three
        } else {
            // leaf nodes
            fmt.Println(item.Value) // will output one-*, two-*, three-* and outernode
        }
    })
  7. Get a string representation of a struct with Repr

    master

    The Repr function is a convenience method that returns a string representation of a struct's values. It internally creates a new tree, performs a valueTree traversal, and returns the resulting string.

    If the input is not a struct, it returns the standard fmt.Sprintf("%+v", val) representation.

    str := treeprint.Repr(myStruct)
    fmt.Println(str)
  8. Render the tree as a string or bytes

    master

    To visualize the tree in ASCII format, use the following methods:

    • String(): Returns the ASCII representation of the tree as a string.
    • Bytes(): Returns the ASCII representation of the tree as a []byte.

    Metadata is rendered in brackets, e.g., ├── [meta] value.

    fmt.Println(tree.String())
  9. Build a tree using AddNode and AddBranch

    master

    The Tree interface provides methods to build the hierarchy. Note that these methods return the Tree interface, allowing for method chaining.

    • AddNode(v Value): Adds a leaf node to the current branch. This node cannot have children.
    • AddMetaNode(meta MetaValue, v Value): Adds a leaf node with an associated metadata value.
    • AddBranch(v Value): Adds a new branch node. This node can subsequently have children added to it.
    • AddMetaBranch(meta MetaValue, v Value): Adds a new branch node with associated metadata.
    • Branch(): Converts the current leaf node into a branch node (allowing children to be added). Calling this on an existing branch has no effect.
    tree := treeprint.NewWithRoot("root")
    
    // Adding branches and nodes
    tree.AddBranch("folder1").
        AddNode("file1.txt").
        AddNode("file2.txt")
    
    tree.AddMetaBranch("meta-info", "folder2").
        AddMetaNode("meta-data", "file3.txt")
  10. Initialize a new tree with New() or NewWithRoot()

    master

    Use New() to create a new tree with a default root value of . or NewWithRoot(root Value) to specify a custom starting value for the root node.

    Both functions return a Tree interface which allows for building and traversing the structure.

    import "github.com/xlab/treeprint"
    
    // Default root ('.')
    tree := treeprint.New()
    
    // Custom root
    tree := treeprint.NewWithRoot("root-name")