Skip to content

Commit

Permalink
feat(tree): add SetChildren, Insert, and Replace to Node interface
Browse files Browse the repository at this point in the history
  • Loading branch information
bashbunni committed Jan 10, 2025
1 parent d60ca5c commit 4d4942c
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 12 deletions.
65 changes: 53 additions & 12 deletions tree/example_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func ExampleNewLeaf() {
//
}

func ExampleNodeChildren_Replace() {
func ExampleTree_Replace() {
enumeratorStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("63")).MarginRight(1)
rootStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("35"))
itemStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("212"))
Expand All @@ -91,21 +91,13 @@ func ExampleNodeChildren_Replace() {
RootStyle(rootStyle).
ItemStyle(itemStyle)
// Add a Tree as a Child of "Glossier"
// This rewrites all of the tree data to do one replace. Not the most
// efficient. Maybe we can improve on this.
//
// That is how we're handling any Child manipulation in the Child() func as
// well. Because the children are an interface it's a bit trickier. We need
// to do an assignment, can't just manipulate the children directly.
t.SetChildren(t.Children().(tree.NodeChildren).
Replace(0, t.Children().At(0).Child(
tree.Root("Apparel").Child("Pink Hoodie", "Baseball Cap"),
)))
t.Replace(0, t.Children().At(0).Child(
tree.Root("Apparel").Child("Pink Hoodie", "Baseball Cap"),
))

// Add a Leaf as a Child of "Glossier"
t.Children().At(0).Child("Makeup")
fmt.Println(ansi.Strip(t.String()))

// Output:
// ⁜ Makeup
// ├── Glossier
Expand All @@ -122,6 +114,55 @@ func ExampleNodeChildren_Replace() {
//
}

func ExampleTree_Insert() {
// Styles are here in case we want to test that styles are properly inherited...
enumeratorStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("63")).MarginRight(1)
rootStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("35"))
itemStyle := lipgloss.NewStyle().Foreground(lipgloss.Color("212"))

t := tree.
Root("⁜ Makeup").
Child(
"Glossier",
"Fenty Beauty",
tree.New().Child(
"Gloss Bomb Universal Lip Luminizer",
"Hot Cheeks Velour Blushlighter",
),
"Nyx",
"Mac",
"Milk",
).
Enumerator(tree.RoundedEnumerator).
EnumeratorStyle(enumeratorStyle).
RootStyle(rootStyle).
ItemStyle(itemStyle)
// Adds a new Tree Node after Fenty Beauty
t.Insert(2, tree.Root("Lancôme").Child("Juicy Tubes Lip Gloss", "Lash Idôle", "Teint Idôle Highlighter"))

// Adds a new Tree Node in Fenty Beauty
t.Replace(1, t.Children().At(1).Insert(0, tree.NewLeaf("Blurring Skin Tint", false)))

// Adds a new Tree Node to a Leaf (Mac)
t.Replace(4, t.Children().At(4).Insert(0, tree.NewLeaf("Glow Play Cushion Blush", false)))
fmt.Println(ansi.Strip(t.String()))
// Output:
//⁜ Makeup
//├── Glossier
//├── Fenty Beauty
//│ ├── Blurring Skin Tint
//│ ├── Gloss Bomb Universal Lip Luminizer
//│ ╰── Hot Cheeks Velour Blushlighter
//├── Lancôme
//│ ├── Juicy Tubes Lip Gloss
//│ ├── Lash Idôle
//│ ╰── Teint Idôle Highlighter
//├── Nyx
//├── Mac
//│ ╰── Glow Play Cushion Blush
//╰── Milk
}

// Tree Examples

func ExampleTree_Hide() {
Expand Down
69 changes: 69 additions & 0 deletions tree/tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ type Node interface {
SetHidden(bool)
SetValue(any)
Child(...any) *Tree
SetChildren(...any) *Tree
Insert(int, any) *Tree
Replace(int, any) *Tree
}

// Leaf is a node without children.
Expand Down Expand Up @@ -89,6 +92,21 @@ func (s *Leaf) Child(children ...any) *Tree {
return t.Child(children)
}

// SetChildren turns the Leaf into a Tree with the given children.
func (s *Leaf) SetChildren(children ...any) *Tree {
return s.Child(children)
}

// Replace turns the Leaf into a Tree with the given child.
func (s *Leaf) Replace(_ int, child any) *Tree {
return s.Child(child)
}

// Insert turns the Leaf into a Tree with the given child.
func (s *Leaf) Insert(_ int, child any) *Tree {
return s.Child(child)
}

// Hidden returns whether a Leaf node is hidden.
func (s Leaf) Hidden() bool {
return s.hidden
Expand Down Expand Up @@ -169,6 +187,57 @@ func (t *Tree) SetChildren(children ...any) *Tree {
return t.Child(children)
}

// Replace swaps the child at the given index with the given child.
func (t *Tree) Replace(index int, child any) *Tree {
nodes := t.anyToNode(child)
t.children = t.children.(NodeChildren).Replace(index, nodes[0])
return t
}

// Insert child at the given index.
func (t *Tree) Insert(index int, child any) *Tree {
nodes := t.anyToNode(child)
t.children = t.children.(NodeChildren).Insert(index, nodes[0])
return t
}

// TODO probably don't need this to be an []any

Check failure on line 204 in tree/tree.go

View workflow job for this annotation

GitHub Actions / lint / lint-soft (ubuntu-latest)

Comment should end in a period (godot)

Check failure on line 204 in tree/tree.go

View workflow job for this annotation

GitHub Actions / lint / lint-soft (macos-latest)

Comment should end in a period (godot)

Check failure on line 204 in tree/tree.go

View workflow job for this annotation

GitHub Actions / lint / lint-soft (macos-latest)

Comment should end in a period (godot)

Check failure on line 204 in tree/tree.go

View workflow job for this annotation

GitHub Actions / lint / lint-soft (windows-latest)

Comment should end in a period (godot)
func (t *Tree) anyToNode(children ...any) []Node {
var nodes []Node
for _, child := range children {
switch item := child.(type) {
case *Tree:
child, _ := child.(*Tree)
nodes = append(nodes, child)
case Children:
for i := 0; i < item.Length(); i++ {
nodes = append(nodes, item.At(i))
}
case Node:
nodes = append(nodes, item)
case fmt.Stringer:
s := Leaf{value: item.String()}
nodes = append(nodes, &s)
case string:
s := Leaf{value: item}
nodes = append(nodes, &s)
case []any:
return t.anyToNode(item...)
case []string:
ss := make([]any, 0, len(item))
for _, s := range item {
ss = append(ss, s)
}
return t.anyToNode(ss...)
case nil:
continue
default:
return t.anyToNode(fmt.Sprintf("%v", item))
}
}
return nodes
}

// Child adds a child to this Tree.
//
// If a Child Tree is passed without a root, it will be parented to it's sibling
Expand Down

0 comments on commit 4d4942c

Please sign in to comment.