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: use tree enumerators #339

Closed
wants to merge 11 commits into from
65 changes: 65 additions & 0 deletions examples/list/tree/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package main

import (
"fmt"

"github.com/charmbracelet/lipgloss/list"
)

func main() {
t := list.New().
Root("~").
Items(
"Documents",
"Downloads",
"Unfinished Projects").
Enumerator(list.Tree)

fmt.Println("A classic tree:\n" + t.String() + "\n")

tr := list.New().
Root("~").
Items(
"Documents",
"Downloads",
"Unfinished Projects").
Enumerator(list.TreeRounded)

fmt.Println("A cool, rounded tree:\n" + tr.String() + "\n")

ti := list.New().
Root("~").
Items(
list.New().
Root("Documents").
Items(
"Important Documents",
"Junk Drawer",
"Books",
).Enumerator(list.Tree),
"Downloads",
"Unfinished Projects").
Enumerator(list.Tree).
Indenter(list.TreeIndenter)

fmt.Println("A fancy, nested tree:\n" + ti.String() + "\n")

documents := list.New().
Root("Documents").
Items(
"Important Documents",
"Junk Drawer",
"Books").
Enumerator(list.Tree)

treeAsRoot := list.New().
Root(documents).
Items(
"More Documents",
"Unfinished Projects",
list.New("Bubble Tea in Rust", "Zig Projects").Enumerator(list.Tree)).
Enumerator(list.Tree).
Indenter(list.TreeIndenter)

fmt.Println("A chaotic tree:\n" + treeAsRoot.String() + "\n")
}
20 changes: 16 additions & 4 deletions internal/tree/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,13 +302,25 @@ func (t *Tree) Children() Children {
// It is a shorthand for:
//
// tree.New().Root(root)
func Root(root string) *Tree {
return New().Root(root)
func Root(root any) *Tree {
t := New()
return t.Root(root)
}

// Root sets the root value of this tree.
func (t *Tree) Root(root string) *Tree {
t.value = root
func (t *Tree) Root(root any) *Tree {
// root is a tree or string
switch item := root.(type) {
case *Tree:
t.value = item.value
t = t.Child(item.children)
case Node, fmt.Stringer:
t.value = item.(fmt.Stringer).String()
case string, nil:
t.value = item.(string)
default:
t.value = fmt.Sprintf("%v", item)
}
return t
}

Expand Down
24 changes: 15 additions & 9 deletions list/enumerator.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
import (
"fmt"
"strings"

"github.com/charmbracelet/lipgloss/internal/tree"
)

// Enumerator enumerates a list. Given a list of items and the index of the
Expand Down Expand Up @@ -128,13 +130,20 @@
// ├── Baz
// └── Qux.
func Tree(items Items, index int) string {
if items.Length()-1 == index {
return "└──"
}
return "├──"
return tree.DefaultEnumerator(items, index)
}

// TreeRounded enumerates a tree with rounded corners.
//
// Foo
// ├── Bar
// ├── Baz
// ╰── Qux

Check failure on line 141 in list/enumerator.go

View workflow job for this annotation

GitHub Actions / lint-soft

Comment should end in a period (godot)
func TreeRounded(items Items, index int) string {
return tree.RoundedEnumerator(items, index)
}

// DefaultIndenter indents a tree for nested trees and multiline content.
// TreeIndenter indents a tree for nested trees and multiline content.
//
// ├── Foo
// ├── Bar
Expand All @@ -145,8 +154,5 @@
// │ └── Quuux
// └── Baz.
func TreeIndenter(items Items, index int) string {
if items.Length()-1 == index {
return " "
}
return "│ "
return tree.DefaultIndenter(items, index)
}
14 changes: 13 additions & 1 deletion list/list.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ import (
// List represents a list of items that can be displayed. Lists can contain
// lists as items, they will be rendered as nested (sub)lists.
//
// In fact, lists can contain anything as items, like lipgloss.Table or lipgloss.Tree.
// In fact, lists can contain anything as items, like lipgloss.Table.
type List struct{ tree *tree.Tree }

// New returns a new list with the given items.
Expand Down Expand Up @@ -80,6 +80,18 @@ type Items tree.Children
// })
type StyleFunc func(items Items, index int) lipgloss.Style

// Root sets the title of the list. For the best results, use this for the
// outermost list.
func (l *List) Root(root any) *List {
switch item := root.(type) {
case *List:
l.tree.Root(item.tree)
default:
l.tree.Root(item)
}
return l
}

// Hidden returns whether this list is hidden.
func (l *List) Hidden() bool {
return l.tree.Hidden()
Expand Down
4 changes: 1 addition & 3 deletions style.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,9 +303,7 @@ func (s Style) Render(strs ...string) string {
te = te.Underline()
}
if reverse {
if reverse {
teWhitespace = teWhitespace.Reverse()
}
teWhitespace = teWhitespace.Reverse()
te = te.Reverse()
}
if blink {
Expand Down
Loading