diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 16:12:43 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 16:12:43 +0000 |
commit | e28e21a9397e402a78499ceeef63dd19989be29e (patch) | |
tree | f4b7f6aaa6bb1563cac5f10b0bde8b6333ac4e37 /bar_filler_bar.go | |
parent | Initial commit. (diff) | |
download | golang-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.go | 291 |
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 +} |