Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions examples/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,7 @@ require (
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
)

replace github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.1 => ../../lipgloss

replace github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1 => ../../bubbles

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

6 changes: 1 addition & 5 deletions examples/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -12,16 +12,12 @@ github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWp
github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA=
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1 h1:swACzss0FjnyPz1enfX56GKkLiuKg5FlyVmOLIlU2kE=
github.com/charmbracelet/bubbles/v2 v2.0.0-beta.1/go.mod h1:6HamsBKWqEC/FVHuQMHgQL+knPyvHH55HwJDHl/adMw=
github.com/charmbracelet/colorprofile v0.3.0 h1:KtLh9uuu1RCt+Hml4s6Hz+kB1PfV3wi++1h5ia65yKQ=
github.com/charmbracelet/colorprofile v0.3.0/go.mod h1:oHJ340RS2nmG1zRGPmhJKJ/jf4FPNNk0P39/wBPA1G0=
github.com/charmbracelet/glamour/v2 v2.0.0-20250327182525-cd9a02a87169 h1:e7EonUlg7tnyBROD7J+C6bI3ndLF7Zh62UGd7d60ORM=
github.com/charmbracelet/glamour/v2 v2.0.0-20250327182525-cd9a02a87169 h1:iYcV8iYgPqnil9uK1Y1VmMTjEnOjjQD9SbYn4sejMRs=
github.com/charmbracelet/glamour/v2 v2.0.0-20250327182525-cd9a02a87169/go.mod h1:4iwRPRwCj2jWI3odZnAPqc1nyCXDuBlnfkGavmjl9NI=
github.com/charmbracelet/harmonica v0.2.0 h1:8NxJWRWg/bzKqqEaaeFNipOu77YR5t8aSwG4pgaUBiQ=
github.com/charmbracelet/harmonica v0.2.0/go.mod h1:KSri/1RMQOZLbw7AHqgcBycp8pgJnQMYYT8QZRqZ1Ao=
github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.1 h1:D9AJJuYTN5pvz6mpIGO1ijLKpfTYSHOtKGgwoTQ4Gog=
github.com/charmbracelet/lipgloss/v2 v2.0.0-beta.1/go.mod h1:tRlx/Hu0lo/j9viunCN2H+Ze6JrmdjQlXUQvvArgaOc=
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
github.com/charmbracelet/x/cellbuf v0.0.14-0.20250326144200-0875329e71da h1:8MGKD5WBtuzfXglq0CnyzVSwGojv57X+H46OL9OUyRA=
Expand Down
62 changes: 62 additions & 0 deletions examples/tree-default/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package main

import (
"fmt"
"os"

"github.com/charmbracelet/bubbles/v2/tree"
tea "github.com/charmbracelet/bubbletea/v2"
)

type model struct {
tree tree.Model
}

func (m model) Init() tea.Cmd {
return nil
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.KeyPressMsg:
switch msg.String() {
case "q", "ctrl+c":
return m, tea.Quit
}
}
m.tree, cmd = m.tree.Update(msg)
return m, cmd
}

func (m model) View() string {
return m.tree.View()
}

func main() {
t := tree.New(tree.Root("~/charm").
Child(
"ayman",
tree.Root("bash").
Child(
tree.Root("tools").
Child("zsh",
"doom-emacs",
),
),
tree.Root("carlos").
Child(
tree.Root("emotes").
Child(
"chefkiss.png",
"kekw.png",
),
),
"maas",
), 70, 13)

if _, err := tea.NewProgram(model{tree: t}).Run(); err != nil {
fmt.Println("Oh no:", err)
os.Exit(1)
}
}
142 changes: 142 additions & 0 deletions examples/tree-file-system/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package main

import (
"fmt"
"os"

"github.com/charmbracelet/bubbles/v2/key"
"github.com/charmbracelet/bubbles/v2/tree"
tea "github.com/charmbracelet/bubbletea/v2"
"github.com/charmbracelet/lipgloss/v2"
ltree "github.com/charmbracelet/lipgloss/v2/tree"
"github.com/charmbracelet/x/ansi"
)

type model struct {
tree tree.Model
choice *tree.Node
}

func (m model) Init() tea.Cmd {
return nil
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.KeyPressMsg:
switch msg.String() {
case "e":
m.choice = m.tree.NodeAtCurrentOffset()
return m, tea.Quit
case "q", "ctrl+c":
return m, tea.Quit
}
}
m.tree, cmd = m.tree.Update(msg)
m.updateStyles()

return m, cmd
}

func (m *model) updateStyles() {
dimmed := lipgloss.Color("239")
base := lipgloss.NewStyle()
m.tree.SetStyles(tree.Styles{
TreeStyle: base.
Padding(1).
Border(lipgloss.RoundedBorder()).
BorderForeground(lipgloss.Color("236")).
BorderBackground(base.GetBackground()),
RootNodeStyle: base,
NodeStyle: base,
ParentNodeStyle: base,
OpenIndicatorStyle: base,
SelectedNodeStyle: base.Bold(true).Background(lipgloss.Color("8")),
HelpStyle: base.MarginTop(1),
EnumeratorStyle: base.Foreground(dimmed),
IndenterStyle: base.Foreground(dimmed),
})
}

func (m model) View() string {
return m.tree.View()
}

type file struct {
name string
color string
}

func (f file) String() string {
return "⌯ " + lipgloss.NewStyle().Foreground(lipgloss.Color(f.color)).Render(f.name)
}

type dir struct {
name string
}

func (d dir) String() string {
return lipgloss.NewStyle().Foreground(lipgloss.Color("4")).Render(d.name)
}

const (
width = 50
height = 21
enumeratorWidth = 3
)

func main() {
t := tree.New(
tree.Root(dir{"charmbracelet/lipgloss"}).
Indenter(func(_ ltree.Children, _ int) string {
return "│ "
}).
Enumerator(func(_ ltree.Children, _ int) string {
return "│ "
}).
Child(
tree.Root(dir{"tree"}).
Child(file{"tree.go", "6"}).
Child(file{"renderer.go", "6"}),
).
Child(
tree.Root(dir{"table"}).
Child(
tree.Root(dir{"utils"}).
Child(file{"utils.go", "6"}),
),
).
Child(tree.Root(dir{"list"}).Child(lipgloss.NewStyle().Faint(true).Render("(empty)"))).
Child(file{"README.md", "3"}).
Child(file{"go.mod", "255"}).
Child(file{"go.sum", "255"}).
Child(file{".gitignore", "255"}),
width,
height,
)
t.SetCursorCharacter("")
t.SetOpenCharacter("📂")
t.SetClosedCharacter("📁")
kb := []key.Binding{
key.NewBinding(key.WithKeys("e"), key.WithHelp("e", "select")),
}
t.AdditionalShortHelpKeys = func() []key.Binding {
return kb
}
t.AdditionalFullHelpKeys = func() []key.Binding {
return kb
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You'll need to update these two because of charmbracelet/bubbles#639 (comment)


p := tea.NewProgram(model{tree: t})
m, err := p.Run()
if err != nil {
fmt.Println("Oh no:", err)
os.Exit(1)
}

// Assert the final tea.Model to our local model and print the choice.
if m, ok := m.(model); ok && m.choice != nil {
fmt.Printf("---\nYou chose %s!\n", ansi.Strip(m.choice.Value()))
}
}
63 changes: 63 additions & 0 deletions examples/tree-long/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package main

import (
"fmt"
"os"
"time"

"github.com/charmbracelet/bubbles/v2/tree"
tea "github.com/charmbracelet/bubbletea/v2"
"github.com/charmbracelet/lipgloss/v2"
)

type model struct {
tree tree.Model
}

func (m model) Init() tea.Cmd {
return nil
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
switch msg := msg.(type) {
case tea.KeyPressMsg:
switch msg.String() {
case "q", "ctrl+c":
return m, tea.Quit
}
}
m.tree, cmd = m.tree.Update(msg)
return m, cmd
}

func (m model) View() string {
return m.tree.View()
}

func main() {
root := tree.Root("🛂 Passport expiration date")
thisYear := time.Now().Year()
for year := thisYear; year < thisYear+10; year++ {
yRoot := tree.Root(fmt.Sprintf("%d", year)).Close()
for month := 1; month <= 12; month++ {
mRoot := tree.Root(time.Month(month).String()).Close().RootStyle(lipgloss.NewStyle().Foreground(lipgloss.Color("1")))
for day := 1; day < daysIn(time.Month(month), year); day++ {
mRoot.Child(fmt.Sprintf("%d", day))
}
yRoot.Child(mRoot)
}
root.Child(yRoot)
}

t := tree.New(root, 80, 30)

if _, err := tea.NewProgram(model{tree: t}).Run(); err != nil {
fmt.Println("Oh no:", err)
os.Exit(1)
}
}

func daysIn(m time.Month, year int) int {
return time.Date(year, m+1, 0, 0, 0, 0, 0, time.UTC).Day()
}
Loading