Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

selection widget fails silently on empty choice list #27

Open
dcopso opened this issue Sep 26, 2023 · 0 comments
Open

selection widget fails silently on empty choice list #27

dcopso opened this issue Sep 26, 2023 · 0 comments

Comments

@dcopso
Copy link

dcopso commented Sep 26, 2023

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():

  • Init() will return tea.Quit if choices is empty. This was very time consuming to track down.
  • The widget requires a non-empty array of choices.
  • In composed models where the set of choices might be empty, the lifecycle of the selection widget should not be managed via the Init() method of the parent model, unless early termination of the program is desirable.

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!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant