charmbracelet / bubbletea

A powerful little TUI framework 🏗

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

add a CmdFunc function

tgirod opened this issue · comments

Here is a little helper function that I would find useful to have in bubbletea:

func CmdFunc(msg tea.Msg) tea.Cmd {
    return func() { return msg }
}

It is very similar to http.HandlerFunc and serves a similar purpose, I think.

Hi there! Curious, what's your use case? Also, assuming you meant this, right?

func CmdFunc(msg tea.Msg) tea.Cmd {
    return func() tea.Msg { return msg }
}

@meowgorithm for my first application, my main model contains a stack of models. The idea is that Update and View are delegating the work to the top-most model of the stack, appart from a few navigation messages that allows to push or pop models from the stack.

// Update takes this model and push it on the stack
type OpenMsg tea.Model

// Update removes topmost model from the stack
type CloseMsg struct{}

// some model Foo

func (f Foo) Update(tea.Msg) (tea.Model, tea.Cmd) {

    // some condition where we want to open model Bar
    bar := OpenMsg(Bar{}) // my new model to display
    return CmdFunc(bar) // send the model back to the Update loop
}

As I find myself turning a tea.Model into a tea.Cmd, I thought it would be useful to have this helper function. Now, maybe I'm approaching the problem the wrong way, and I shouldn't have to do that ... In which case I'm eager to be corrected! :)

So logic dictates that you shouldn't need to use a Cmd to simply send data to different parts of your application because that data already exists in the very Update from which you're returning the Cmd.

That said, while this is probably fine to use in practicality (we see it every so often) it does incur an unnecessary loop through the runtime. Because of that, we'd prefer not to include it in the core. In other words, it's techincally an antipattern, and actually a common one seen in The Elm Architecture, the design upon which Bubble Tea is built.

So logic dictates that you shouldn't need to use a Cmd to simply send data to different parts of your application because that data already exists in the very Update from which you're returning the Cmd.

Thanks for your input! I think I oversimplified my example, and in that case CmdFunc is effectively useless. I'll try to do better this time.

// main model
type Main struct {
    stack []tea.Model
}

// first sub-model
type Screen1 struct {}

// second sub-model
type Screen2 struct{}

In Main.Update, messages are passed to the top-most model in the stack, appart from special messages to push/pop models on the stack.

Now, Let's say Screen1 is the top-most model in the stack. Following an event, some code in Screen1.Update creates a Screen2 model which should be pushed to the stack. So, I would say the data exists in Screen1.Update, but not in Main.Update, right?

Or am I creating components, and I should avoid doing that, as ELM's documentation suggests?

Hey @tgirod when you say data I'm assuming you mean Screen2 and all its data?
Typically what you'd want to do here is manage the state of the program in the main model, then change what's being shown from View based on the main model's state. In this case you would want to control the creation of new screens in your main model's Update. If the new Screen2 is created while you're looking at Screen1 don't worry, you can still handle the tea.Msg in the main Update and just trigger the tea.Cmd from your Screen1 Update. I hope this answers your question. Please let me know if not, and I'll be happy to try again 😄