Make spinners ignore tick messsages send by other spinners

This commit is contained in:
Christian Rocha 2021-12-01 11:33:48 -05:00
parent f09987549a
commit 94b84b6120

View File

@ -2,6 +2,7 @@ package spinner
import ( import (
"strings" "strings"
"sync"
"time" "time"
tea "github.com/charmbracelet/bubbletea" tea "github.com/charmbracelet/bubbletea"
@ -9,6 +10,21 @@ import (
"github.com/muesli/reflow/ansi" "github.com/muesli/reflow/ansi"
) )
// Internal ID management for text inputs. Necessary for blink integrity when
// multiple text inputs are involved.
var (
lastID int
idMtx sync.Mutex
)
// Return the next ID we should use on the Model.
func nextID() int {
idMtx.Lock()
defer idMtx.Unlock()
lastID++
return lastID
}
// Spinner is a set of frames used in animating the spinner. // Spinner is a set of frames used in animating the spinner.
type Spinner struct { type Spinner struct {
Frames []string Frames []string
@ -92,6 +108,7 @@ type Model struct {
frame int frame int
startTime time.Time startTime time.Time
id int
tag int tag int
} }
@ -173,13 +190,17 @@ func (m Model) Visible() bool {
// NewModel returns a model with default values. // NewModel returns a model with default values.
func NewModel() Model { func NewModel() Model {
return Model{Spinner: Line} return Model{
Spinner: Line,
id: nextID(),
}
} }
// TickMsg indicates that the timer has ticked and we should render a frame. // TickMsg indicates that the timer has ticked and we should render a frame.
type TickMsg struct { type TickMsg struct {
Time time.Time Time time.Time
tag int tag int
id int
} }
// Update is the Tea update function. This will advance the spinner one frame // Update is the Tea update function. This will advance the spinner one frame
@ -188,6 +209,12 @@ type TickMsg struct {
func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) { func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
switch msg := msg.(type) { switch msg := msg.(type) {
case TickMsg: case TickMsg:
// If an ID is set, and the ID doesn't belong to this spinner, reject
// the message.
if msg.id > 0 && msg.id != m.id {
return m, nil
}
// If a tag is set, and it's not the one we expect, reject the message. // If a tag is set, and it's not the one we expect, reject the message.
// This prevents the spinner from receiving too many messages and // This prevents the spinner from receiving too many messages and
// thus spinning too fast. // thus spinning too fast.
@ -201,7 +228,7 @@ func (m Model) Update(msg tea.Msg) (Model, tea.Cmd) {
} }
m.tag++ m.tag++
return m, m.tick(m.tag) return m, m.tick(m.id, m.tag)
default: default:
return m, nil return m, nil
} }
@ -231,10 +258,11 @@ func Tick() tea.Msg {
return TickMsg{Time: time.Now()} return TickMsg{Time: time.Now()}
} }
func (m Model) tick(tag int) tea.Cmd { func (m Model) tick(id, tag int) tea.Cmd {
return tea.Tick(m.Spinner.FPS, func(t time.Time) tea.Msg { return tea.Tick(m.Spinner.FPS, func(t time.Time) tea.Msg {
return TickMsg{ return TickMsg{
Time: t, Time: t,
id: id,
tag: tag, tag: tag,
} }
}) })