bubbles/spinner/spinner.go

119 lines
2.9 KiB
Go
Raw Normal View History

2020-02-10 19:40:52 +03:00
package spinner
import (
"time"
tea "github.com/charmbracelet/bubbletea"
2020-03-27 21:10:09 +03:00
"github.com/muesli/termenv"
2020-02-10 19:40:52 +03:00
)
// Spinner is a set of frames used in animating the spinner.
2020-02-10 19:51:08 +03:00
type Spinner = int
// Available types of spinners
const (
Line Spinner = iota
Dot
)
const (
defaultFPS = 9
)
2020-02-10 19:40:52 +03:00
var (
2020-02-10 19:51:08 +03:00
// Spinner frames
spinners = map[Spinner][]string{
2020-04-22 21:29:30 +03:00
Line: {"|", "/", "-", "\\"},
Dot: {"⣾ ", "⣽ ", "⣻ ", "⢿ ", "⡿ ", "⣟ ", "⣯ ", "⣷ "},
2020-02-10 19:51:08 +03:00
}
2020-03-27 21:10:09 +03:00
color = termenv.ColorProfile().Color
2020-02-10 19:40:52 +03:00
)
// Model contains the state for the spinner. Use NewModel to create new models
// rather than using Model as a struct literal.
type Model struct {
// Type is the set of frames to use. See Spinner.
Type Spinner
// FPS is the speed at which the ticker should tick
FPS int
// ForegroundColor sets the background color of the spinner. It can be a
// hex code or one of the 256 ANSI colors. If the terminal emulator can't
// doesn't support the color specified it will automatically degrade
// (per github.com/muesli/termenv).
2020-03-27 21:10:09 +03:00
ForegroundColor string
// BackgroundColor sets the background color of the spinner. It can be a
// hex code or one of the 256 ANSI colors. If the terminal emulator can't
// doesn't support the color specified it will automatically degrade
// (per github.com/muesli/termenv).
2020-03-27 21:10:09 +03:00
BackgroundColor string
// CustomMsgFunc can be used to a custom message on tick. This can be
// useful when you have spinners in different parts of your application and
// want to differentiate between the messages for clarity and simplicity.
// If nil, this setting is ignored.
CustomMsgFunc func() tea.Msg
2020-02-10 19:40:52 +03:00
frame int
}
// NewModel returns a model with default values.
2020-02-10 19:40:52 +03:00
func NewModel() Model {
return Model{
Type: Line,
FPS: defaultFPS,
2020-02-10 19:40:52 +03:00
}
}
// TickMsg indicates that the timer has ticked and we should render a frame.
type TickMsg struct{}
2020-02-10 19:40:52 +03:00
// Update is the Tea update function. This will advance the spinner one frame
// every time it's called, regardless the message passed, so be sure the logic
// is setup so as not to call this Update needlessly.
2020-02-10 19:40:52 +03:00
func Update(msg tea.Msg, m Model) (Model, tea.Cmd) {
m.frame++
if m.frame >= len(spinners[m.Type]) {
m.frame = 0
}
if m.CustomMsgFunc != nil {
return m, Tick(m)
2020-02-10 19:40:52 +03:00
}
return m, Tick(m)
2020-02-10 19:40:52 +03:00
}
// View renders the model's view.
2020-02-10 19:40:52 +03:00
func View(model Model) string {
2020-02-10 19:51:08 +03:00
s := spinners[model.Type]
if model.frame >= len(s) {
2020-02-10 19:40:52 +03:00
return "[error]"
}
2020-03-27 21:10:09 +03:00
str := s[model.frame]
if model.ForegroundColor != "" || model.BackgroundColor != "" {
return termenv.
String(str).
Foreground(color(model.ForegroundColor)).
Background(color(model.BackgroundColor)).
String()
}
return str
2020-02-10 19:40:52 +03:00
}
// Tick is the command used to advance the spinner one frame.
func Tick(model Model) tea.Cmd {
return func() tea.Msg {
time.Sleep(time.Second / time.Duration(model.FPS))
if model.CustomMsgFunc != nil {
return model.CustomMsgFunc()
}
return TickMsg{}
2020-02-10 19:40:52 +03:00
}
}