Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(tree): hide children #454

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
15 changes: 12 additions & 3 deletions tree/renderer.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,18 @@ func (r *renderer) render(node Node, root bool, prefix string) string {
}

for i := 0; i < children.Length(); i++ {
prefix := enumerator(children, i)
prefix = r.style.enumeratorFunc(children, i).Render(prefix)
maxLen = max(lipgloss.Width(prefix), maxLen)
if i < children.Length()-1 {
if child := children.At(i + 1); child.Hidden() {
// Don't count the last child if its hidden. This renders the
// last visible element with the right prefix
//
// The only type of Children is NodeChildren.
children = children.(NodeChildren).Remove(i + 1)
}
prefix := enumerator(children, i)
prefix = r.style.enumeratorFunc(children, i).Render(prefix)
maxLen = max(lipgloss.Width(prefix), maxLen)
}
}

for i := 0; i < children.Length(); i++ {
Expand Down
51 changes: 41 additions & 10 deletions tree/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
Value() string
Children() Children
Hidden() bool
SetHidden(bool)
SetValue(any)
}

// Leaf is a node without children.
Expand All @@ -46,21 +48,44 @@
hidden bool
}

// NewLeaf returns a new Leaf.
func NewLeaf(value any, hidden bool) *Leaf {
s := Leaf{}
s.SetValue(value)
s.SetHidden(hidden)
return &s
}

// Children of a Leaf node are always empty.
func (Leaf) Children() Children {
return NodeChildren(nil)
}

// Value of a leaf node returns its value.
// Value returns the value of a Leaf node.
func (s Leaf) Value() string {
return s.value
}

// SetValue sets the value of a Leaf node.
func (s *Leaf) SetValue(value any) {
switch item := value.(type) {
case Node, fmt.Stringer:
s.value = item.(fmt.Stringer).String()
case string, nil:
s.value = item.(string)
default:
s.value = fmt.Sprintf("%v", item)
}
}

// Hidden returns whether a Leaf node is hidden.
func (s Leaf) Hidden() bool {
return s.hidden
}

// SetHidden hides a Leaf node.
func (s *Leaf) SetHidden(hidden bool) { s.hidden = hidden }

// String returns the string representation of a Leaf node.
func (s Leaf) String() string {
return s.Value()
Expand All @@ -77,18 +102,22 @@
ronce sync.Once
}

// Hidden returns whether this node is hidden.
// Hidden returns whether a Tree node is hidden.
func (t *Tree) Hidden() bool {
return t.hidden
}

// Hide sets whether to hide the tree node.
// Hide sets whether to hide the Tree node. Use this when creating a new
// hidden Tree.
func (t *Tree) Hide(hide bool) *Tree {
t.hidden = hide
return t
}

// Offset sets the tree children offsets.
// SetHidden hides a Tree node.
func (t *Tree) SetHidden(hidden bool) { t.Hide(hidden) }

// Offset sets the Tree children offsets.
func (t *Tree) Offset(start, end int) *Tree {
if start > end {
_start := start
Expand All @@ -113,12 +142,17 @@
return t.value
}

// String returns the string representation of the tree node.
// SetValue sets the value of a Tree node.
func (t *Tree) SetValue(value any) {
t = t.Root(value)

Check failure on line 147 in tree/tree.go

View workflow job for this annotation

GitHub Actions / lint / lint (ubuntu-latest)

ineffectual assignment to t (ineffassign)

Check failure on line 147 in tree/tree.go

View workflow job for this annotation

GitHub Actions / lint / lint (macos-latest)

ineffectual assignment to t (ineffassign)

Check failure on line 147 in tree/tree.go

View workflow job for this annotation

GitHub Actions / lint / lint (ubuntu-latest)

ineffectual assignment to t (ineffassign)
bashbunni marked this conversation as resolved.
Show resolved Hide resolved
}

// String returns the string representation of the Tree node.
func (t *Tree) String() string {
return t.ensureRenderer().render(t, true, "")
}

// Child adds a child to this tree.
// Child adds a child to this Tree.
//
// If a Child Tree is passed without a root, it will be parented to it's sibling
// child (auto-nesting).
Expand Down Expand Up @@ -147,7 +181,7 @@
t.children = t.children.(NodeChildren).Append(item)
case fmt.Stringer:
s := Leaf{value: item.String()}
t.children = t.children.(NodeChildren).Append(s)
t.children = t.children.(NodeChildren).Append(&s)
case string:
s := Leaf{value: item}
t.children = t.children.(NodeChildren).Append(&s)
Expand Down Expand Up @@ -180,9 +214,6 @@
parent.Child(item.children.At(i))
}
return parent, j
case Leaf:
item.value = parent.Value()
return item, j
case *Leaf:
item.value = parent.Value()
return item, j
Expand Down
86 changes: 86 additions & 0 deletions tree/tree_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package tree_test

import (
"fmt"
"strings"
"testing"
"unicode"
Expand Down Expand Up @@ -705,6 +706,33 @@ func TestTypes(t *testing.T) {
assertEqual(t, want, tree.String())
}

func TestLeafHidden(t *testing.T) {
tr := tree.New().
Child(
"Foo",
tree.Root("Bar").
Child(
"Qux",
tree.Root("Quux").
Child("This should be hidden").
Hide(true),
"Quuux",
),
"Baz",
)

// Hide Qux.
tr.Children().At(1).Children().At(0).SetHidden(true)

want := `
├── Foo
├── Bar
│ └── Quuux
└── Baz
`
assertEqual(t, want, tr.String())
}

// assertEqual verifies the strings are equal, assuming its terminal output.
func assertEqual(tb testing.TB, want, got string) {
tb.Helper()
Expand All @@ -729,3 +757,61 @@ func trimSpace(s string) string {
}
return strings.Join(result, "\n")
}

func ExampleLeaf_SetHidden() {
tr := tree.New().
Child(
"Foo",
tree.Root("Bar").
Child(
"Qux",
tree.Root("Quux").
Child("Hello!"),
"Quuux",
),
"Baz",
)

tr.Children().At(1).Children().At(2).SetHidden(true)
fmt.Println(tr.String())
// Output:
//
// ├── Foo
// ├── Bar
// │ ├── Qux
// │ └── Quux
// │ └── Hello!
// └── Baz
//
}

func ExampleNewLeaf() {
tr := tree.New().
Child(
"Foo",
tree.Root("Bar").
Child(
"Qux",
tree.Root("Quux").
Child(
tree.NewLeaf("This should be hidden", true),
tree.NewLeaf(
tree.Root("I am groot").Child("leaves"), false),
),
"Quuux",
),
"Baz",
)

fmt.Println(tr.String())
// Output:
// ├── Foo
// ├── Bar
// │ ├── Qux
// │ ├── Quux
// │ │ └── I am groot
// │ │ └── leaves
// │ └── Quuux
// └── Baz
//
}
Loading