package main
import (
"fmt"
"os"
tea "charm.land/bubbletea/v2"
)
func main() {
p := tea.NewProgram(initMainMenu())
_, err := p.Run()
if err != nil {
fmt.Printf("there was an error: %v\n", err)
os.Exit(1)
}
}
func initMainMenu() tea.Model {
return *NewCharmingMap2("menu 0", []CharmingOption2{
{Option: "menu 1", Result: initMenu1},
{Option: "menu 2", Result: initMenu2},
}, "press q to exit", nil)
}
func initMenu1() tea.Model {
return *NewCharmingMap2("menu 1", nil, "press q to exit, <- to go back", initMainMenu)
}
func initMenu2() tea.Model {
return *NewCharmingMap2("menu 2", []CharmingOption2{
{Option: "menu 3", Result: initMenu3},
}, "press q to exit, <- to go back", initMainMenu)
}
func initMenu3() tea.Model {
return *NewCharmingMap2("menu 3", nil, "press q to exit, <- to go back", initMenu2)
}
type CharmingOption2 struct {
Option string
Result func() tea.Model
}
func NewCharm2(option string, result func() tea.Model) CharmingOption2 {
return CharmingOption2{option, result}
}
type CharmingMap2 struct {
title string
footer string
options []string
cursor int
results []func() tea.Model
back func() tea.Model
}
func NewCharmingMap2(title string, options []CharmingOption2, footer string, back func() tea.Model) *CharmingMap2 {
optionTexts := []string{}
results := []func() tea.Model{}
for _, option := range options {
optionTexts = append(optionTexts, option.Option)
results = append(results, option.Result)
}
return &CharmingMap2{
title: title,
footer: footer,
options: optionTexts,
cursor: 0,
results: results,
back: back,
}
}
// ----- TUI functions -----
func (m CharmingMap2) Init() tea.Cmd {
return nil
}
func (m CharmingMap2) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.KeyPressMsg:
switch msg.String() {
case "ctrl+c", "q":
return m, tea.Quit
case "up", "k":
if len(m.options) > 0 {
if m.cursor > 0 {
m.cursor--
} else {
m.cursor = len(m.options) - 1
}
}
case "down", "j":
if len(m.options) > 0 {
if m.cursor < len(m.options)-1 {
m.cursor++
} else {
m.cursor = 0
}
}
case "enter", "space", "right":
if m.cursor < len(m.results) {
if m.results[m.cursor] != nil {
return m.results[m.cursor](), nil
} else {
// doesn't get deleted
return m, tea.Println("no result defined, i'm in " + m.title)
}
} else {
// gets deleted by new view render
return m, tea.Println("no childs found, i'm in " + m.title)
}
case "backspace", "left":
if m.back != nil {
return m.back(), nil
}
}
}
return m, nil
}
func (m CharmingMap2) View() tea.View {
s := m.title
s += "\n\n"
// draw options
for i, option := range m.options {
cursor := " "
if m.cursor == i {
cursor = ">"
}
s += fmt.Sprintf(" %s %s\n", cursor, option)
}
// the footer
s += "\n" + m.footer + "\n"
return tea.NewView(s)
}
Describe the bug
I'm trying to make a generic and recursive menu navigation model.
I want to add some kind of logs with tea.Println.
When I'm in a menu, generate a specific println call and go back, the new view is printed on top of the latest println text instead of below it.
Step by step: Menu 0 -> Menu 1 -> is empty, enter twice, go back, latest println gets printed on top.
Setup
Please complete the following information along with version numbers, if applicable.
To Reproduce
Steps to reproduce the behavior:
Source Code
Click to see the code
---Expected behavior
New view is printed below the latest println line.