Okay, I think that's how error handling should work

This commit is contained in:
Christian Rocha 2020-01-18 10:13:44 -05:00
parent 9909356eb7
commit d976902768
No known key found for this signature in database
GPG Key ID: D6CC7A16E5878018
2 changed files with 57 additions and 25 deletions

View File

@ -3,6 +3,7 @@ package main
// A simple program that counts down from 5 and then exits.
import (
"errors"
"fmt"
"log"
"tea"
@ -10,8 +11,9 @@ import (
"tea/input"
)
type model struct {
input input.Model
type Model struct {
Input input.Model
Error error
}
type tickMsg struct{}
@ -20,19 +22,21 @@ func main() {
tea.UseSysLog("tea")
p := tea.NewProgram(
model{
input: input.DefaultModel(),
Model{
Input: input.DefaultModel(),
Error: nil,
},
update,
view,
[]tea.Sub{
// Just hand off the subscription to the input component
func(m tea.Model) tea.Msg {
if m, ok := m.(model); ok {
return input.Blink(m.input)
// We just hand off the subscription to the input component, giving
// it the model it expects.
func(model tea.Model) tea.Msg {
m, ok := model.(Model)
if !ok {
return tea.NewErrMsg("could not perform assertion on model")
}
// TODO: return error
return nil
return input.Blink(m.Input)
},
},
)
@ -42,9 +46,16 @@ func main() {
}
}
func update(msg tea.Msg, mdl tea.Model) (tea.Model, tea.Cmd) {
func update(msg tea.Msg, model tea.Model) (tea.Model, tea.Cmd) {
var cmd tea.Cmd
m, _ := mdl.(model)
m, ok := model.(Model)
if !ok {
// When we encounter errors in Update we simply add the error to the
// model so we can handle it in the view. We could also return a command
// that does something else with the error, like logs it via IO.
m.Error = errors.New("could not perform assertion on model")
return m, nil
}
switch msg := msg.(type) {
case tea.KeyMsg:
@ -54,22 +65,27 @@ func update(msg tea.Msg, mdl tea.Model) (tea.Model, tea.Cmd) {
case "esc":
return m, tea.Quit
}
// We handle errors just like any other message
case tea.ErrMsg:
m.Error = msg
return m, nil
}
m.input, cmd = input.Update(msg, m.input)
m.Input, cmd = input.Update(msg, m.Input)
return m, cmd
}
func view(m tea.Model) string {
if m, ok := m.(model); ok {
help := "(esc to exit)"
return fmt.Sprintf(
"Whats your favorite Pokémon?\n\n%s\n\n%s",
input.View(m.input),
help,
)
func view(model tea.Model) string {
m, ok := model.(Model)
if !ok {
return "Oh no: could not perform assertion on model."
} else if m.Error != nil {
return fmt.Sprintf("Uh oh: %s", m.Error)
}
// TODO: return error
return ""
return fmt.Sprintf(
"Whats your favorite Pokémon?\n\n%s\n\n%s",
input.View(m.Input),
"(esc to quit)",
)
}

18
tea.go
View File

@ -1,6 +1,7 @@
package tea
import (
"errors"
"fmt"
"io"
"log"
@ -44,6 +45,22 @@ type Program struct {
rw io.ReadWriter
}
// ErrMsg is just a regular message containing an error. We handle it in Update
// just like a regular message by case switching. Of course, the developer
// could also define her own errors as well.
type ErrMsg struct {
error
}
func (e ErrMsg) String() string {
return e.Error()
}
// NewErrMsg is a convenience function for creating a generic ErrMsg
func NewErrMsg(s string) ErrMsg {
return ErrMsg{errors.New(s)}
}
// Quit is a command that tells the program to exit
func Quit() Msg {
return quitMsg{}
@ -63,7 +80,6 @@ func NewProgram(model Model, update Update, view View, subs []Sub) *Program {
}
// Start initializes the program
// TODO: error channel
func (p *Program) Start() error {
var (
model = p.model