bubbles/progress/progress.go

111 lines
2.4 KiB
Go
Raw Normal View History

2020-11-04 16:42:44 +03:00
package progress
import (
2020-11-18 22:27:41 +03:00
"fmt"
2020-11-04 16:42:44 +03:00
"strings"
"github.com/lucasb-eyer/go-colorful"
2020-11-18 22:27:41 +03:00
"github.com/muesli/reflow/ansi"
2020-11-04 16:42:44 +03:00
"github.com/muesli/termenv"
)
2020-11-18 23:59:10 +03:00
var color func(string) termenv.Color = termenv.ColorProfile().Color
// Option is used to set options in NewModel. For example:
//
// progress := NewModel(
// WithRamp("#ff0000", "#0000ff"),
// )
type Option func(*Model)
// WithDefaultRamp sets a gradient fill with default colors.
func WithDefaultRamp() Option {
return WithRamp("#00dbde", "#fc00ff")
}
// WithRamp sets a gradient fill blending between two colors.
func WithRamp(colorA, colorB string) Option {
a, _ := colorful.Hex(colorA)
b, _ := colorful.Hex(colorB)
return func(m *Model) {
m.useRamp = true
m.colorA = a
m.colorB = b
}
}
2020-11-04 16:42:44 +03:00
type Model struct {
// Left side color of progress bar. By default, it's #00dbde
colorA colorful.Color
2020-11-04 16:42:44 +03:00
// Left side color of progress bar. By default, it's #fc00ff
colorB colorful.Color
2020-11-04 16:42:44 +03:00
// Total width of the progress bar, including percentage, if set.
2020-11-05 14:41:53 +03:00
Width int
2020-11-04 16:42:44 +03:00
// Rune for "filled" sections of the progress bar.
2020-11-18 22:27:41 +03:00
Full rune
2020-11-04 16:42:44 +03:00
// Rune for "empty" sections of progress bar.
2020-11-18 22:27:41 +03:00
Empty rune
2020-11-04 16:42:44 +03:00
// if true, gradient will be setted from start to end of filled part. Instead, it'll work
// on all proggress bar length
FullGradientMode bool
2020-11-18 22:27:41 +03:00
ShowPercent bool
PercentFormat string
useRamp bool
2020-11-04 16:42:44 +03:00
}
// NewModel returns a model with default values.
func NewModel(opts ...Option) *Model {
m := &Model{
2020-11-18 22:27:41 +03:00
Width: 40,
Full: '█',
Empty: '░',
ShowPercent: true,
PercentFormat: " %3.0f%%",
2020-11-04 16:42:44 +03:00
}
for _, opt := range opts {
opt(m)
}
return m
2020-11-04 16:42:44 +03:00
}
2020-11-18 22:27:41 +03:00
func (m Model) View(percent float64) string {
if m.ShowPercent {
s := fmt.Sprintf(m.PercentFormat, percent*100)
w := ansi.PrintableRuneWidth(s)
return m.bar(percent, w) + s
}
return m.bar(percent, 0)
}
func (m Model) bar(percent float64, textWidth int) string {
w := m.Width - textWidth
ramp := make([]string, int(float64(w)*percent))
2020-11-04 16:42:44 +03:00
for i := 0; i < len(ramp); i++ {
2020-11-18 22:27:41 +03:00
gradientPart := float64(w)
2020-11-04 16:42:44 +03:00
if m.FullGradientMode {
gradientPart = float64(len(ramp))
}
percent := float64(i) / gradientPart
c := m.colorA.BlendLuv(m.colorB, percent)
2020-11-04 16:42:44 +03:00
ramp[i] = c.Hex()
}
var fullCells string
for i := 0; i < len(ramp); i++ {
2020-11-18 23:59:10 +03:00
fullCells += termenv.String(string(m.Full)).Foreground(color(ramp[i])).String()
2020-11-04 16:42:44 +03:00
}
2020-11-18 22:27:41 +03:00
fullCells += strings.Repeat(string(m.Empty), w-len(ramp))
2020-11-04 16:42:44 +03:00
return fullCells
}