summaryrefslogtreecommitdiffstats
path: root/bar_filler_bar.go
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 16:12:43 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-16 16:12:43 +0000
commite28e21a9397e402a78499ceeef63dd19989be29e (patch)
treef4b7f6aaa6bb1563cac5f10b0bde8b6333ac4e37 /bar_filler_bar.go
parentInitial commit. (diff)
downloadgolang-github-vbauerster-mpb-e28e21a9397e402a78499ceeef63dd19989be29e.tar.xz
golang-github-vbauerster-mpb-e28e21a9397e402a78499ceeef63dd19989be29e.zip
Adding upstream version 8.6.1.upstream/8.6.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'bar_filler_bar.go')
-rw-r--r--bar_filler_bar.go291
1 files changed, 291 insertions, 0 deletions
diff --git a/bar_filler_bar.go b/bar_filler_bar.go
new file mode 100644
index 0000000..5d7837a
--- /dev/null
+++ b/bar_filler_bar.go
@@ -0,0 +1,291 @@
+package mpb
+
+import (
+ "io"
+
+ "github.com/mattn/go-runewidth"
+ "github.com/vbauerster/mpb/v8/decor"
+ "github.com/vbauerster/mpb/v8/internal"
+)
+
+const (
+ iLbound = iota
+ iRbound
+ iRefiller
+ iFiller
+ iTip
+ iPadding
+ components
+)
+
+var defaultBarStyle = [components]string{"[", "]", "+", "=", ">", "-"}
+
+// BarStyleComposer interface.
+type BarStyleComposer interface {
+ BarFillerBuilder
+ Lbound(string) BarStyleComposer
+ LboundMeta(func(string) string) BarStyleComposer
+ Rbound(string) BarStyleComposer
+ RboundMeta(func(string) string) BarStyleComposer
+ Filler(string) BarStyleComposer
+ FillerMeta(func(string) string) BarStyleComposer
+ Refiller(string) BarStyleComposer
+ RefillerMeta(func(string) string) BarStyleComposer
+ Padding(string) BarStyleComposer
+ PaddingMeta(func(string) string) BarStyleComposer
+ Tip(frames ...string) BarStyleComposer
+ TipMeta(func(string) string) BarStyleComposer
+ TipOnComplete() BarStyleComposer
+ Reverse() BarStyleComposer
+}
+
+type component struct {
+ width int
+ bytes []byte
+}
+
+type flushSection struct {
+ meta func(io.Writer, []byte) error
+ bytes []byte
+}
+
+type bFiller struct {
+ components [components]component
+ meta [components]func(io.Writer, []byte) error
+ flush func(io.Writer, ...flushSection) error
+ tipOnComplete bool
+ tip struct {
+ frames []component
+ count uint
+ }
+}
+
+type barStyle struct {
+ style [components]string
+ metaFuncs [components]func(io.Writer, []byte) error
+ tipFrames []string
+ tipOnComplete bool
+ rev bool
+}
+
+// BarStyle constructs default bar style which can be altered via
+// BarStyleComposer interface.
+func BarStyle() BarStyleComposer {
+ bs := barStyle{
+ style: defaultBarStyle,
+ tipFrames: []string{defaultBarStyle[iTip]},
+ }
+ for i := range bs.metaFuncs {
+ bs.metaFuncs[i] = defaultMeta
+ }
+ return bs
+}
+
+func (s barStyle) Lbound(bound string) BarStyleComposer {
+ s.style[iLbound] = bound
+ return s
+}
+
+func (s barStyle) LboundMeta(fn func(string) string) BarStyleComposer {
+ s.metaFuncs[iLbound] = makeMetaFunc(fn)
+ return s
+}
+
+func (s barStyle) Rbound(bound string) BarStyleComposer {
+ s.style[iRbound] = bound
+ return s
+}
+
+func (s barStyle) RboundMeta(fn func(string) string) BarStyleComposer {
+ s.metaFuncs[iRbound] = makeMetaFunc(fn)
+ return s
+}
+
+func (s barStyle) Filler(filler string) BarStyleComposer {
+ s.style[iFiller] = filler
+ return s
+}
+
+func (s barStyle) FillerMeta(fn func(string) string) BarStyleComposer {
+ s.metaFuncs[iFiller] = makeMetaFunc(fn)
+ return s
+}
+
+func (s barStyle) Refiller(refiller string) BarStyleComposer {
+ s.style[iRefiller] = refiller
+ return s
+}
+
+func (s barStyle) RefillerMeta(fn func(string) string) BarStyleComposer {
+ s.metaFuncs[iRefiller] = makeMetaFunc(fn)
+ return s
+}
+
+func (s barStyle) Padding(padding string) BarStyleComposer {
+ s.style[iPadding] = padding
+ return s
+}
+
+func (s barStyle) PaddingMeta(fn func(string) string) BarStyleComposer {
+ s.metaFuncs[iPadding] = makeMetaFunc(fn)
+ return s
+}
+
+func (s barStyle) Tip(frames ...string) BarStyleComposer {
+ if len(frames) != 0 {
+ s.tipFrames = frames
+ }
+ return s
+}
+
+func (s barStyle) TipMeta(fn func(string) string) BarStyleComposer {
+ s.metaFuncs[iTip] = makeMetaFunc(fn)
+ return s
+}
+
+func (s barStyle) TipOnComplete() BarStyleComposer {
+ s.tipOnComplete = true
+ return s
+}
+
+func (s barStyle) Reverse() BarStyleComposer {
+ s.rev = true
+ return s
+}
+
+func (s barStyle) Build() BarFiller {
+ bf := &bFiller{
+ meta: s.metaFuncs,
+ tipOnComplete: s.tipOnComplete,
+ }
+ bf.components[iLbound] = component{
+ width: runewidth.StringWidth(s.style[iLbound]),
+ bytes: []byte(s.style[iLbound]),
+ }
+ bf.components[iRbound] = component{
+ width: runewidth.StringWidth(s.style[iRbound]),
+ bytes: []byte(s.style[iRbound]),
+ }
+ bf.components[iFiller] = component{
+ width: runewidth.StringWidth(s.style[iFiller]),
+ bytes: []byte(s.style[iFiller]),
+ }
+ bf.components[iRefiller] = component{
+ width: runewidth.StringWidth(s.style[iRefiller]),
+ bytes: []byte(s.style[iRefiller]),
+ }
+ bf.components[iPadding] = component{
+ width: runewidth.StringWidth(s.style[iPadding]),
+ bytes: []byte(s.style[iPadding]),
+ }
+ bf.tip.frames = make([]component, len(s.tipFrames))
+ for i, t := range s.tipFrames {
+ bf.tip.frames[i] = component{
+ width: runewidth.StringWidth(t),
+ bytes: []byte(t),
+ }
+ }
+ if s.rev {
+ bf.flush = func(w io.Writer, sections ...flushSection) error {
+ for i := len(sections) - 1; i >= 0; i-- {
+ if s := sections[i]; len(s.bytes) != 0 {
+ err := s.meta(w, s.bytes)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+ }
+ } else {
+ bf.flush = func(w io.Writer, sections ...flushSection) error {
+ for _, s := range sections {
+ if len(s.bytes) != 0 {
+ err := s.meta(w, s.bytes)
+ if err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+ }
+ }
+ return bf
+}
+
+func (s *bFiller) Fill(w io.Writer, stat decor.Statistics) error {
+ width := internal.CheckRequestedWidth(stat.RequestedWidth, stat.AvailableWidth)
+ // don't count brackets as progress
+ width -= (s.components[iLbound].width + s.components[iRbound].width)
+ if width < 0 {
+ return nil
+ }
+
+ err := s.meta[iLbound](w, s.components[iLbound].bytes)
+ if err != nil {
+ return err
+ }
+
+ if width == 0 {
+ return s.meta[iRbound](w, s.components[iRbound].bytes)
+ }
+
+ var tip component
+ var refilling, filling, padding []byte
+ var fillCount int
+ curWidth := int(internal.PercentageRound(stat.Total, stat.Current, uint(width)))
+
+ if curWidth != 0 {
+ if !stat.Completed || s.tipOnComplete {
+ tip = s.tip.frames[s.tip.count%uint(len(s.tip.frames))]
+ s.tip.count++
+ fillCount += tip.width
+ }
+ if stat.Refill != 0 {
+ refWidth := int(internal.PercentageRound(stat.Total, stat.Refill, uint(width)))
+ curWidth -= refWidth
+ refWidth += curWidth
+ for w := s.components[iFiller].width; curWidth-fillCount >= w; fillCount += w {
+ filling = append(filling, s.components[iFiller].bytes...)
+ }
+ for w := s.components[iRefiller].width; refWidth-fillCount >= w; fillCount += w {
+ refilling = append(refilling, s.components[iRefiller].bytes...)
+ }
+ } else {
+ for w := s.components[iFiller].width; curWidth-fillCount >= w; fillCount += w {
+ filling = append(filling, s.components[iFiller].bytes...)
+ }
+ }
+ }
+
+ for w := s.components[iPadding].width; width-fillCount >= w; fillCount += w {
+ padding = append(padding, s.components[iPadding].bytes...)
+ }
+
+ for w := 1; width-fillCount >= w; fillCount += w {
+ padding = append(padding, "…"...)
+ }
+
+ err = s.flush(w,
+ flushSection{s.meta[iRefiller], refilling},
+ flushSection{s.meta[iFiller], filling},
+ flushSection{s.meta[iTip], tip.bytes},
+ flushSection{s.meta[iPadding], padding},
+ )
+ if err != nil {
+ return err
+ }
+ return s.meta[iRbound](w, s.components[iRbound].bytes)
+}
+
+func makeMetaFunc(fn func(string) string) func(io.Writer, []byte) error {
+ return func(w io.Writer, p []byte) (err error) {
+ _, err = io.WriteString(w, fn(string(p)))
+ return err
+ }
+}
+
+func defaultMeta(w io.Writer, p []byte) (err error) {
+ _, err = w.Write(p)
+ return err
+}