186 lines
5.3 KiB
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
|
|
}
|