Skip to content

tea.Listen() to automatically listen on a chan tea.Msg #1135

Open
@myaaaaaaaaa

Description

@myaaaaaaaaa

Is your feature request related to a problem? Please describe.

Currently, tea.Cmds 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.Msgs.

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(),
 	})

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions