diff --git a/tutorials/commands/README.md b/tutorials/commands/README.md index 6fcafba..9fedfb5 100644 --- a/tutorials/commands/README.md +++ b/tutorials/commands/README.md @@ -19,18 +19,18 @@ We'll import a few necessary packages and put the URL we're going to check in a `const`. ```go - package main +package main - import ( - "fmt" - "net/http" - "os" - "time" +import ( + "fmt" + "net/http" + "os" + "time" - tea "github.com/charmbracelet/bubbletea" - ) + tea "github.com/charmbracelet/bubbletea" +) - const url = "https://charm.sh/" +const url = "https://charm.sh/" ``` ## The Model @@ -39,10 +39,10 @@ Next we'll define our model. The only things we need to store are the status code of the HTTP response and a possible error. ```go - type model struct { - status int - err error - } +type model struct { + status int + err error +} ``` ## Commands and Messages @@ -56,29 +56,29 @@ Anyway, let's write a `Cmd` that makes a request to a server and returns the result as a `Msg`. ```go - func checkServer() tea.Msg { +func checkServer() tea.Msg { - // Create an HTTP client and make a GET request. - c := &http.Client{Timeout: 10 * time.Second} - res, err := c.Get(url) + // Create an HTTP client and make a GET request. + c := &http.Client{Timeout: 10 * time.Second} + res, err := c.Get(url) - if err != nil { - // There was an error making our request. Wrap the error we received - // in a message and return it. - return errMsg{err} - } - // We received a response from the server. Return the HTTP status code - // as a message. - return statusMsg(res.StatusCode) + if err != nil { + // There was an error making our request. Wrap the error we received + // in a message and return it. + return errMsg{err} } + // We received a response from the server. Return the HTTP status code + // as a message. + return statusMsg(res.StatusCode) +} - type statusMsg int +type statusMsg int - type errMsg struct{ err error } +type errMsg struct{ err error } - // For messages that contain errors it's often handy to also implement the - // error interface on the message. - func (e errMsg) Error() string { return e.err.Error() } +// For messages that contain errors it's often handy to also implement the +// error interface on the message. +func (e errMsg) Error() string { return e.err.Error() } ``` And notice that we've defined two new `Msg` types. They can be any type, even @@ -92,9 +92,9 @@ the `Cmd` we made earlier. Note that we don't call the function; the Bubble Tea runtime will do that when the time is right. ```go - func initialize() (tea.Model, tea.Cmd) { - return model{}, checkServer - } +func initialize() (tea.Model, tea.Cmd) { + return model{}, checkServer +} ``` ## The Update Function @@ -105,37 +105,37 @@ types we made earlier when we were making the `checkServer` command? We handle them here. This makes dealing with many asynchronous operations very easy. ```go - func update(msg tea.Msg, mdl tea.Model) (tea.Model, tea.Cmd) { - m, _ := mdl.(model) +func update(msg tea.Msg, mdl tea.Model) (tea.Model, tea.Cmd) { + m, _ := mdl.(model) - switch msg := msg.(type) { + switch msg := msg.(type) { - case statusMsg: - // The server returned a status message. Save it to our model. Also - // tell the Bubble Tea runtime we ant to exit because we have - // nothing else to do. Don't worry, we'll still be able to render - // a final view with our status message. - m.status = int(msg) + case statusMsg: + // The server returned a status message. Save it to our model. Also + // tell the Bubble Tea runtime we ant to exit because we have + // nothing else to do. Don't worry, we'll still be able to render + // a final view with our status message. + m.status = int(msg) + return m, tea.Quit + + case errMsg: + // There was an error. Note it in the model. And tell the runtime + // we're done and want to quit. + m.err = msg + return m, tea.Quit + + case tea.KeyMsg: + // Ctrl+c exits. Even with short running programs it's good to have + // a quit key, just incase your logic is off. Users will be very + // annoyed if they can't exit. + if msg.Type == tea.KeyCtrlC { return m, tea.Quit - - case errMsg: - // There was an error. Note it in the model. And tell the runtime - // we're done and want to quit. - m.err = msg - return m, tea.Quit - - case tea.KeyMsg: - // Ctrl+c exits. Even with short running programs it's good to have - // a quit key, just incase your logic is off. Users will be very - // annoyed if they can't exit. - if msg.Type == tea.KeyCtrlC { - return m, tea.Quit - } } - - // If we happen to get any other messages, don't do anything. - return m, nil } + + // If we happen to get any other messages, don't do anything. + return m, nil +} ``` ## The View Function @@ -144,25 +144,25 @@ Our view is very straightforward. We look at the current model and build a string accordingly: ```go - func view(mdl tea.Model) string { - m, _ := mdl.(model) +func view(mdl tea.Model) string { + m, _ := mdl.(model) - // If there's an error, print it out and don't do anything else. - if m.err != nil { - return fmt.Sprintf("\nWe had some trouble: %v\n\n", m.err) - } - - // Tell the user we're doing something. - s := fmt.Sprintf("Checking %s ... ", url) - - // When the server responds with a status, add it to the current line. - if m.status > 0 { - s += fmt.Sprintf("%d %s!", m.status, http.StatusText(m.status)) - } - - // Send off whatever we came up with above for rendering. - return "\n" + s + "\n\n" + // If there's an error, print it out and don't do anything else. + if m.err != nil { + return fmt.Sprintf("\nWe had some trouble: %v\n\n", m.err) } + + // Tell the user we're doing something. + s := fmt.Sprintf("Checking %s ... ", url) + + // When the server responds with a status, add it to the current line. + if m.status > 0 { + s += fmt.Sprintf("%d %s!", m.status, http.StatusText(m.status)) + } + + // Send off whatever we came up with above for rendering. + return "\n" + s + "\n\n" +} ``` ## Run the program @@ -170,12 +170,12 @@ string accordingly: The only thing left to do is run the program, so let's do that! ```go - func main() { - if err := tea.NewProgram(initialize, update, view).Start(); err != nil { - fmt.Printf("Uh oh, there was an error: %v\n", err) - os.Exit(1) - } +func main() { + if err := tea.NewProgram(initialize, update, view).Start(); err != nil { + fmt.Printf("Uh oh, there was an error: %v\n", err) + os.Exit(1) } +} ``` And that's that. There's one more thing you that is helpful to know about @@ -189,18 +189,16 @@ anything. If you need to pass arguments to a command, you just make a function that returns a command. For example: ```go - - func checkSomeUrl(url string) tea.Cmd { - return func() tea.Msg { - c := &http.Client{Timeout: 10 * time.Second} - res, err := c.Get(url) - if err != nil { - return errMsg(err) - } - return statusMsg(res.StatusCode) +func checkSomeUrl(url string) tea.Cmd { + return func() tea.Msg { + c := &http.Client{Timeout: 10 * time.Second} + res, err := c.Get(url) + if err != nil { + return errMsg(err) } + return statusMsg(res.StatusCode) } - +} ``` Just make sure you do as much stuff as you can in the innermost function,