erikgeiser / promptkit

Go prompt library
MIT License
249 stars 21 forks source link

selection widget fails silently on empty choice list #27

Open dcopso opened 1 year ago

dcopso commented 1 year ago

When the choices array is empty, selection.Model.Init() sets an error and returns tea.Quit. The error state cannot be reliably reacted to in Update or View because there seems to be a race condition in BubbleTea where sometimes the program exits before Update or View is called.

It would be helpful if the following behaviors were described in the documentation on selection.New, selection.NewModel, and Model.Init():

Also, the program hangs forever if the model.selection field is changed from *selection.Model[string] to selection.Model[string]. This is surprising.

This program, run multiple times with debug build, demonstrates the race and the exit:

package main

import (
    "fmt"
    tea "github.com/charmbracelet/bubbletea"
    "github.com/erikgeiser/promptkit/selection"
)

type model struct {
    selection *selection.Model[string]
}

func (m model) Init() tea.Cmd {
    return m.selection.Init() // Bug: this returns tea.Quit when .choices is empty array.
}

func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
    if m.selection.Err != nil {
        panic(fmt.Sprintf("promptkit err: %v", m.selection.Err)) // race: sometimes enters this block
    }
    return m.selection.Update(msg)
}

func (m model) View() string {
    if m.selection.Err != nil {
        return fmt.Sprintf("promptkit err: %v", m.selection.Err) // never seems to enter this block
    }
    return m.selection.View()
}

func main() {
    mySelection := selection.New("Prompt", []string{})
    mySelectionModel := selection.NewModel(mySelection)
    myModel := model{
        selection: mySelectionModel,
    }
    p := tea.NewProgram(myModel)
    if _, err := p.Run(); err != nil {
        panic(err)
    }
}

Thanks!