6
0
mirror of https://github.com/grdl/git-get.git synced 2026-02-04 20:19:42 +00:00
Files
git-get/pkg/print/smart.go
Grzegorz Dlugoszewski 32211e6408 Cleanup the print package
- Use strings.Builder instead of concatenation
- Move smart tree to a separate file
- Add missing docstrings
2020-06-18 19:20:03 +02:00

99 lines
3.0 KiB
Go

package print
import (
"git-get/pkg/repo"
"path/filepath"
"strings"
)
// SmartPrinter implements Printer interface and provides methods for printing repos and their statuses.
// It's "smart" because it automatically folds branches which only have a single child and indents branches with many children.
type SmartPrinter struct {
// length is the size (number of chars) of the currently processed line.
// It's used to correctly indent the lines with branches status.
length int
}
// Print generates a list of repositories and their statuses.
func (p *SmartPrinter) Print(root string, repos []*repo.Repo) string {
tree := buildTree(root, repos)
return p.printSmartTree(tree)
}
// printSmartTree recursively traverses the tree and prints its nodes.
// If a node contains multiple children, they are be printed in new lines and indented.
// If a node contains only a single child, it is printed in the same line using path separator.
// For better readability the first level (repos hosts) is not indented.
//
// Example:
// Following paths:
// /repos/github.com/user/repo1
// /repos/github.com/user/repo2
// /repos/github.com/another/repo
//
// will render a tree:
// /repos/
// github.com/
// user/
// repo1
// repo2
// another/repo
//
func (p *SmartPrinter) printSmartTree(node *Node) string {
if node.children == nil {
// If node is a leaf, print repo name and its status and finish processing this node.
value := node.val
// TODO: Ugly
// If this is called from tests the repo will be nil and we should return just the name without the status.
if node.repo.Repository == nil {
return value
}
value += " " + printWorktreeStatus(node.repo)
// Print the status of each branch on a new line, indented to match the position of the current branch name.
indent := "\n" + strings.Repeat(" ", p.length+len(node.val))
for _, branch := range node.repo.Status.Branches {
// Don't print the status of the current branch. It was already printed above.
if branch.Name == node.repo.Status.CurrentBranch {
continue
}
value += indent + printBranchStatus(branch)
}
return value
}
val := node.val + string(filepath.Separator)
shift := ""
if node.parent == nil {
// If node is a root, print its children on a new line without indentation.
shift = "\n"
} else if len(node.children) == 1 {
// If node has only a single child, print it on the same line as its parent.
// Setting node's depth to the same as parent's ensures that its children will be indented only once even if
// node's path has multiple levels above.
node.depth = node.parent.depth
p.length += len(val)
} else {
// If node has multiple children, print each of them on a new line
// and indent them once relative to the parent
node.depth = node.parent.depth + 1
shift = "\n" + strings.Repeat(" ", node.depth)
p.length = 0
}
for _, child := range node.children {
p.length += len(shift)
val += shift + p.printSmartTree(child)
p.length = 0
}
return val
}