charmbracelet / bubbletea

A powerful little TUI framework 🏗
MIT License
26.76k stars 771 forks source link

List Model is not full screen #245

Closed gitpubber closed 2 years ago

gitpubber commented 2 years ago

Hello, thanks for bubbletea. It's really good. I am developing TUI using bubbletea. It's search program which takes input from user and displays list. I was experimenting with prototype. I wanted to have perspective of "Pages" in bubbletea(for ex. Main Page, Search Page , List Page)

Here is the code:

main.go

package main

import (
    "fmt"
    "os"

    "github.com/charmbracelet/bubbles/list"
    "github.com/charmbracelet/bubbles/textinput"
    tea "github.com/charmbracelet/bubbletea"
    "github.com/charmbracelet/lipgloss"
)

func main() {
    if err := tea.NewProgram(mainModel(), tea.WithAltScreen()).Start(); err != nil {
        fmt.Println("Error running program:", err)
        os.Exit(1)
    }
}

type item struct {
    title, desc string
}

func (i item) Title() string       { return i.title }
func (i item) Description() string { return i.desc }
func (i item) FilterValue() string { return i.title }

var docStyle = lipgloss.NewStyle().Margin(1, 2)

type uiState int

const (
    uiMainPage uiState = iota
    uiListPage
)

type model struct {
    uiState   uiState
    textInput textinput.Model
    myList    list.Model
    err       error
}

func mainModel() model {
    ti := textinput.New()
    ti.Focus()
    //ti.CharLimit = 156
    //ti.Width = 20

    return model{
        uiState:   uiMainPage,
        textInput: ti,
        err:       nil,
    }
}

func (m model) Init() tea.Cmd {
    switch m.uiState {
    case uiMainPage:
        return textinput.Blink
    case uiListPage:
        return nil
    }
    return nil
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    switch m.uiState {
    case uiMainPage:
        switch msg := msg.(type) {
        case tea.KeyMsg:
            switch msg.Type {
            case tea.KeyCtrlC, tea.KeyEsc:
                return m, tea.Quit
            case tea.KeyEnter:
                items := []list.Item{
                    item{title: "Raspberry Pi’s", desc: "I have ’em all over my house"},
                    item{title: "Nutella", desc: "It's good on toast"},
                    item{title: "Bitter melon", desc: "It cools you down"},
                    item{title: "Nice socks", desc: "And by that I mean socks without holes"},
                    item{title: "Eight hours of sleep", desc: "I had this once"},
                    item{title: "Cats", desc: "Usually"},
                    item{title: "Plantasia, the album", desc: "My plants love it too"},
                    item{title: "Pour over coffee", desc: "It takes forever to make though"},
                    item{title: "VR", desc: "Virtual reality...what is there to say?"},
                    item{title: "Noguchi Lamps", desc: "Such pleasing organic forms"},
                    item{title: "Linux", desc: "Pretty much the best OS"},
                    item{title: "Business school", desc: "Just kidding"},
                    item{title: "Pottery", desc: "Wet clay is a great feeling"},
                    item{title: "Shampoo", desc: "Nothing like clean hair"},
                    item{title: "Table tennis", desc: "It’s surprisingly exhausting"},
                    item{title: "Milk crates", desc: "Great for packing in your extra stuff"},
                    item{title: "Afternoon tea", desc: "Especially the tea sandwich part"},
                    item{title: "Stickers", desc: "The thicker the vinyl the better"},
                    item{title: "20° Weather", desc: "Celsius, not Fahrenheit"},
                    item{title: "Warm light", desc: "Like around 2700 Kelvin"},
                    item{title: "The vernal equinox", desc: "The autumnal equinox is pretty good too"},
                    item{title: "Gaffer’s tape", desc: "Basically sticky fabric"},
                    item{title: "Terrycloth", desc: "In other words, towel fabric"},
                }

                m.myList = list.New(items, list.NewDefaultDelegate(), 0, 0)
                m.myList.Title = "My Fave Things"
                m.uiState = uiListPage
                var cmd tea.Cmd
                m.myList, cmd = m.myList.Update(msg)
                return m, cmd
            }
        }

        var cmd tea.Cmd
        m.textInput, cmd = m.textInput.Update(msg)
        return m, cmd
    case uiListPage:
        switch msg := msg.(type) {
        case tea.KeyMsg:
            if msg.String() == "ctrl+c" {
                return m, tea.Quit
            }
        case tea.WindowSizeMsg:
            top, right, bottom, left := docStyle.GetMargin()
            m.myList.SetSize(msg.Width-left-right, msg.Height-top-bottom)
        }

        var cmd tea.Cmd
        m.myList, cmd = m.myList.Update(msg)
        return m, cmd

    default:
        return m, nil
    }
}

func (m model) View() string {
    switch m.uiState {
    case uiMainPage:
        return fmt.Sprintf(
            "Search: \n\n%s\n\n%s",
            m.textInput.View(),
            "(esc to quit)",
        ) + "\n"
    case uiListPage:
        return docStyle.Render(m.myList.View())
    default:
        return ""
    }
}

Problem is that list only shows one element(unless terminal is resized) whereas i wanted it to be fullscreen.

This is what I wanted: image

This is what I get: image

Only one element is displayed.

Please help me.

muesli commented 2 years ago

At first glance it looks like your list simply doesn't have the right dimensions because it never receives an initial tea.WindowSizeMsg. I assume resizing your terminal would make the list snap back to an appropriate size?

If you want to dynamically initialize the list you would have to remember the last tea.WindowSizeMsg in your model and call m.myList.SetSize after creating the list.

gitpubber commented 2 years ago

@muesli , Yeah. That was the problem. I saved WindowSizeMsg as state in model. while switching to listview,I set it. Now,it's properly working.

But,it would be nicer if listview automatically does this though.