bubbletea
bubbletea copied to clipboard
`tea.Listen()` to automatically listen on a `chan tea.Msg`
Is your feature request related to a problem? Please describe.
Currently, tea.Cmd
s can only send a single tea.Msg
before terminating, making things awkward when there is a need for a continuously running function that sends multiple tea.Msg
s.
This can be seen in the realtime example, where a wrapper function waitForActivity()
must be used to relay messages from listenForActivity()
.
Describe the solution you'd like
A tea.Listen(func(chan<- tea.Msg)) tea.Cmd
function to accompany functions like tea.Batch()
or tea.Every()
. It should create a chan tea.Msg
, pass it to the given function and run it in a separate goroutine, and relay messages that it receives on said channel to the Update()
function.
Below is how the realtime example would be changed. Note how there is no longer a need to manually resend waitForActivity()
commands or pass around a channel.
diff --git a/examples/realtime/main.go b/examples/realtime/main.go
index 4abddd3..1e1a71c 100644
--- a/examples/realtime/main.go
+++ b/examples/realtime/main.go
@@ -21,25 +21,15 @@ type responseMsg struct{}
-func listenForActivity(sub chan struct{}) tea.Cmd {
- return func() tea.Msg {
- for {
- time.Sleep(time.Millisecond * time.Duration(rand.Int63n(900)+100)) // nolint:gosec
- sub <- struct{}{}
- }
- }
-}
-
-// A command that waits for the activity on a channel.
-func waitForActivity(sub chan struct{}) tea.Cmd {
- return func() tea.Msg {
- return responseMsg(<-sub)
+func listenForActivity(sub chan<- tea.Msg) {
+ for {
+ time.Sleep(time.Millisecond * time.Duration(rand.Int63n(900)+100)) // nolint:gosec
+ sub <- responseMsg{}
}
}
type model struct {
- sub chan struct{} // where we'll receive activity notifications
- responses int // how many responses we've received
+ responses int // how many responses we've received
spinner spinner.Model
quitting bool
}
@@ -47,8 +37,7 @@ type model struct {
func (m model) Init() tea.Cmd {
return tea.Batch(
m.spinner.Tick,
- listenForActivity(m.sub), // generate activity
- waitForActivity(m.sub), // wait for activity
+ tea.Listen(listenForActivity), // generate activity
)
}
@@ -58,8 +47,8 @@ func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
case responseMsg:
- m.responses++ // record external activity
- return m, waitForActivity(m.sub) // wait for next event
+ m.responses++ // record external activity
+ return m, nil
@@ -79,7 +68,6 @@ func (m model) View() string {
p := tea.NewProgram(model{
- sub: make(chan struct{}),
spinner: spinner.New(),
})