Skip to content

Commit

Permalink
chore: revert "refactor: remove shim compat layer and tea.Model"
Browse files Browse the repository at this point in the history
This reverts commit 46f89ce and parts
of 8f62296
  • Loading branch information
aymanbagabas committed Jan 29, 2025
1 parent 423a0e4 commit 67f8ede
Showing 1 changed file with 35 additions and 1 deletion.
36 changes: 35 additions & 1 deletion tea.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,23 @@ var ErrInterrupted = errors.New("program was interrupted")
// function and, henceforth, the UI.
type Msg interface{}

// Model contains the program's state as well as its core functions.
type Model[T any] interface {
// Init is the first function that will be called. It returns an optional
// initial command. To not perform an initial command return nil.
Init() (T, Cmd)

// Update is called when a message is received. Use it to inspect messages
// and, in response, update the model and/or send a command.
Update(Msg) (T, Cmd)

// View renders the program's UI, which is just a [fmt.Stringer]. The view
// is rendered after every Update.
// The main model can return a [Frame] to set the cursor position and
// style.
View() fmt.Stringer
}

// Cmd is an IO operation that returns a message when it's complete. If it's
// nil it's considered a no-op. Use it for things like HTTP requests, timers,
// saving and loading from disk, and so on.
Expand Down Expand Up @@ -142,7 +159,7 @@ type Program[T any] struct {
// To have more control over the cursor position and style, you can use
// [Frame.Cursor] and [NewCursor] to position the cursor and define its
// style.
View func(T) Frame
View func(T) fmt.Stringer

// Model contains the last state of the program. If the program hasn't
// started yet, it will be nil. After the program finish executing, it will
Expand Down Expand Up @@ -275,6 +292,15 @@ func Interrupt() Msg {
return InterruptMsg{}
}

// NewProgram creates a new Program.
func NewProgram[T any](model Model[T]) *Program[T] {
p := new(Program[T])
p.Init = model.Init
p.Update = func(t T, msg Msg) (T, Cmd) { return any(t).(Model[T]).Update(msg) }
p.View = func(t T) fmt.Stringer { return any(t).(Model[T]).View() }
return p
}

func (p *Program[T]) init() {
if atomic.LoadInt32(&p.initialized) == 1 {
return
Expand Down Expand Up @@ -695,6 +721,14 @@ func (p *Program[T]) eventLoop(cmds chan Cmd) {
p.Model, cmd = p.Update(p.Model, msg) // run update
cmds <- cmd // process command (if any)
view := p.View(p.Model)
switch view := view.(type) {
case Frame:
// Ensure we reset the cursor color on exit.
if view.Cursor != nil {
p.setCc = view.Cursor.Color
}
}

p.renderer.render(view) //nolint:errcheck // send view to renderer
}
}
Expand Down

0 comments on commit 67f8ede

Please sign in to comment.