mirror of https://github.com/containers/podman.git
174 lines
3.3 KiB
Go
174 lines
3.3 KiB
Go
package mpb
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"unicode/utf8"
|
|
|
|
"github.com/mattn/go-runewidth"
|
|
"github.com/vbauerster/mpb/v5/decor"
|
|
"github.com/vbauerster/mpb/v5/internal"
|
|
)
|
|
|
|
const (
|
|
rLeft = iota
|
|
rFill
|
|
rTip
|
|
rSpace
|
|
rRight
|
|
rRevTip
|
|
rRefill
|
|
)
|
|
|
|
// DefaultBarStyle is a string containing 7 runes.
|
|
// Each rune is a building block of a progress bar.
|
|
//
|
|
// '1st rune' stands for left boundary rune
|
|
//
|
|
// '2nd rune' stands for fill rune
|
|
//
|
|
// '3rd rune' stands for tip rune
|
|
//
|
|
// '4th rune' stands for space rune
|
|
//
|
|
// '5th rune' stands for right boundary rune
|
|
//
|
|
// '6th rune' stands for reverse tip rune
|
|
//
|
|
// '7th rune' stands for refill rune
|
|
//
|
|
const DefaultBarStyle string = "[=>-]<+"
|
|
|
|
type barFiller struct {
|
|
format [][]byte
|
|
rwidth []int
|
|
tip []byte
|
|
refill int64
|
|
reverse bool
|
|
flush func(io.Writer, *space, [][]byte)
|
|
}
|
|
|
|
type space struct {
|
|
space []byte
|
|
rwidth int
|
|
count int
|
|
}
|
|
|
|
// NewBarFiller constucts mpb.BarFiller, to be used with *Progress.Add(...) *Bar method.
|
|
func NewBarFiller(style string, reverse bool) BarFiller {
|
|
bf := &barFiller{
|
|
format: make([][]byte, len(DefaultBarStyle)),
|
|
rwidth: make([]int, len(DefaultBarStyle)),
|
|
reverse: reverse,
|
|
}
|
|
bf.SetStyle(style)
|
|
return bf
|
|
}
|
|
|
|
func (s *barFiller) SetStyle(style string) {
|
|
if !utf8.ValidString(style) {
|
|
panic("invalid bar style")
|
|
}
|
|
if style == "" {
|
|
style = DefaultBarStyle
|
|
}
|
|
src := make([][]byte, utf8.RuneCountInString(style))
|
|
i := 0
|
|
for _, r := range style {
|
|
s.rwidth[i] = runewidth.RuneWidth(r)
|
|
src[i] = []byte(string(r))
|
|
i++
|
|
}
|
|
copy(s.format, src)
|
|
s.SetReverse(s.reverse)
|
|
}
|
|
|
|
func (s *barFiller) SetReverse(reverse bool) {
|
|
if reverse {
|
|
s.tip = s.format[rRevTip]
|
|
s.flush = reverseFlush
|
|
} else {
|
|
s.tip = s.format[rTip]
|
|
s.flush = regularFlush
|
|
}
|
|
s.reverse = reverse
|
|
}
|
|
|
|
func (s *barFiller) Fill(w io.Writer, reqWidth int, stat decor.Statistics) {
|
|
width := internal.WidthForBarFiller(reqWidth, stat.AvailableWidth)
|
|
|
|
if brackets := s.rwidth[rLeft] + s.rwidth[rRight]; width < brackets {
|
|
return
|
|
} else {
|
|
// don't count brackets as progress
|
|
width -= brackets
|
|
}
|
|
w.Write(s.format[rLeft])
|
|
defer w.Write(s.format[rRight])
|
|
|
|
cwidth := int(internal.PercentageRound(stat.Total, stat.Current, width))
|
|
space := &space{
|
|
space: s.format[rSpace],
|
|
rwidth: s.rwidth[rSpace],
|
|
count: width - cwidth,
|
|
}
|
|
|
|
index, refill := 0, 0
|
|
bb := make([][]byte, cwidth)
|
|
|
|
if cwidth > 0 && cwidth != width {
|
|
bb[index] = s.tip
|
|
cwidth -= s.rwidth[rTip]
|
|
index++
|
|
}
|
|
|
|
if stat.Refill > 0 {
|
|
refill = int(internal.PercentageRound(stat.Total, int64(stat.Refill), width))
|
|
if refill > cwidth {
|
|
refill = cwidth
|
|
}
|
|
cwidth -= refill
|
|
}
|
|
|
|
for cwidth > 0 {
|
|
bb[index] = s.format[rFill]
|
|
cwidth -= s.rwidth[rFill]
|
|
index++
|
|
}
|
|
|
|
for refill > 0 {
|
|
bb[index] = s.format[rRefill]
|
|
refill -= s.rwidth[rRefill]
|
|
index++
|
|
}
|
|
|
|
if cwidth+refill < 0 || space.rwidth > 1 {
|
|
buf := new(bytes.Buffer)
|
|
s.flush(buf, space, bb[:index])
|
|
io.WriteString(w, runewidth.Truncate(buf.String(), width, "…"))
|
|
return
|
|
}
|
|
|
|
s.flush(w, space, bb)
|
|
}
|
|
|
|
func regularFlush(w io.Writer, space *space, bb [][]byte) {
|
|
for i := len(bb) - 1; i >= 0; i-- {
|
|
w.Write(bb[i])
|
|
}
|
|
for space.count > 0 {
|
|
w.Write(space.space)
|
|
space.count -= space.rwidth
|
|
}
|
|
}
|
|
|
|
func reverseFlush(w io.Writer, space *space, bb [][]byte) {
|
|
for space.count > 0 {
|
|
w.Write(space.space)
|
|
space.count -= space.rwidth
|
|
}
|
|
for i := 0; i < len(bb); i++ {
|
|
w.Write(bb[i])
|
|
}
|
|
}
|