mfer/vendor/github.com/pterm/pterm/tree_printer.go

186 lines
5.3 KiB
Go

package pterm
import (
"strings"
)
// TreeNode is used as items in a TreePrinter.
type TreeNode struct {
Children []TreeNode
Text string
}
// LeveledList is a list, which contains multiple LeveledListItem.
type LeveledList []LeveledListItem
// LeveledListItem combines a text with a specific level.
// The level is the indent, which would normally be seen in a BulletListPrinter.
type LeveledListItem struct {
Level int
Text string
}
// DefaultTree contains standards, which can be used to render a TreePrinter.
var DefaultTree = TreePrinter{
TreeStyle: &ThemeDefault.TreeStyle,
TextStyle: &ThemeDefault.TreeTextStyle,
TopRightCornerString: "└",
HorizontalString: "─",
TopRightDownString: "├",
VerticalString: "│",
RightDownLeftString: "┬",
Indent: 2,
}
// TreePrinter is able to render a list.
type TreePrinter struct {
Root TreeNode
TreeStyle *Style
TextStyle *Style
TopRightCornerString string
TopRightDownString string
HorizontalString string
VerticalString string
RightDownLeftString string
Indent int
}
// WithTreeStyle returns a new list with a specific tree style.
func (p TreePrinter) WithTreeStyle(style *Style) *TreePrinter {
p.TreeStyle = style
return &p
}
// WithTextStyle returns a new list with a specific text style.
func (p TreePrinter) WithTextStyle(style *Style) *TreePrinter {
p.TextStyle = style
return &p
}
// WithTopRightCornerString returns a new list with a specific TopRightCornerString.
func (p TreePrinter) WithTopRightCornerString(s string) *TreePrinter {
p.TopRightCornerString = s
return &p
}
// WithTopRightDownStringOngoing returns a new list with a specific TopRightDownString.
func (p TreePrinter) WithTopRightDownStringOngoing(s string) *TreePrinter {
p.TopRightDownString = s
return &p
}
// WithHorizontalString returns a new list with a specific HorizontalString.
func (p TreePrinter) WithHorizontalString(s string) *TreePrinter {
p.HorizontalString = s
return &p
}
// WithVerticalString returns a new list with a specific VerticalString.
func (p TreePrinter) WithVerticalString(s string) *TreePrinter {
p.VerticalString = s
return &p
}
// WithRoot returns a new list with a specific Root.
func (p TreePrinter) WithRoot(root TreeNode) *TreePrinter {
p.Root = root
return &p
}
// WithIndent returns a new list with a specific amount of spacing between the levels.
// Indent must be at least 1.
func (p TreePrinter) WithIndent(indent int) *TreePrinter {
if indent < 1 {
indent = 1
}
p.Indent = indent
return &p
}
// Render prints the list to the terminal.
func (p TreePrinter) Render() error {
s, _ := p.Srender()
Println(s)
return nil
}
// Srender renders the list as a string.
func (p TreePrinter) Srender() (string, error) {
if p.TreeStyle == nil {
p.TreeStyle = NewStyle()
}
if p.TextStyle == nil {
p.TextStyle = NewStyle()
}
return walkOverTree(p.Root.Children, p, ""), nil
}
// walkOverTree is a recursive function,
// which analyzes a TreePrinter and connects the items with specific characters.
// Returns TreePrinter as string.
func walkOverTree(list []TreeNode, p TreePrinter, prefix string) string {
var ret string
for i, item := range list {
if len(list) > i+1 { // if not last in list
if len(item.Children) == 0 { // if there are no children
ret += prefix + p.TreeStyle.Sprint(p.TopRightDownString) + strings.Repeat(p.TreeStyle.Sprint(p.HorizontalString), p.Indent) +
p.TextStyle.Sprint(item.Text) + "\n"
} else { // if there are children
ret += prefix + p.TreeStyle.Sprint(p.TopRightDownString) + strings.Repeat(p.TreeStyle.Sprint(p.HorizontalString), p.Indent-1) +
p.TreeStyle.Sprint(p.RightDownLeftString) + p.TextStyle.Sprint(item.Text) + "\n"
ret += walkOverTree(item.Children, p, prefix+p.TreeStyle.Sprint(p.VerticalString)+strings.Repeat(" ", p.Indent-1))
}
} else if len(list) == i+1 { // if last in list
if len(item.Children) == 0 { // if there are no children
ret += prefix + p.TreeStyle.Sprint(p.TopRightCornerString) + strings.Repeat(p.TreeStyle.Sprint(p.HorizontalString), p.Indent) +
p.TextStyle.Sprint(item.Text) + "\n"
} else { // if there are children
ret += prefix + p.TreeStyle.Sprint(p.TopRightCornerString) + strings.Repeat(p.TreeStyle.Sprint(p.HorizontalString), p.Indent-1) +
p.TreeStyle.Sprint(p.RightDownLeftString) + p.TextStyle.Sprint(item.Text) + "\n"
ret += walkOverTree(item.Children, p, prefix+strings.Repeat(" ", p.Indent))
}
}
}
return ret
}
// NewTreeFromLeveledList converts a TreeItems list to a TreeNode and returns it.
func NewTreeFromLeveledList(leveledListItems LeveledList) TreeNode {
if len(leveledListItems) == 0 {
return TreeNode{}
}
root := &TreeNode{
Children: []TreeNode{},
Text: leveledListItems[0].Text,
}
for i, record := range leveledListItems {
last := root
if record.Level < 0 {
record.Level = 0
leveledListItems[i].Level = 0
}
if len(leveledListItems)-1 != i {
if leveledListItems[i+1].Level-1 > record.Level {
leveledListItems[i+1].Level = record.Level + 1
}
}
for i := 0; i < record.Level; i++ {
lastIndex := len(last.Children) - 1
last = &last.Children[lastIndex]
}
last.Children = append(last.Children, TreeNode{
Children: []TreeNode{},
Text: record.Text,
})
}
return *root
}