diff --git a/bar_filler.go b/bar_filler.go index a08e7d1..0d751a6 100644 --- a/bar_filler.go +++ b/bar_filler.go @@ -18,25 +18,46 @@ rRefill ) -var defaultBarStyle = "[=>-]<+" +// DefaultBarStyle is applied when bar constructed with *Progress.AddBar method. +// +// '1th rune' stands for left boundary rune +// +// '2th rune' stands for fill rune +// +// '3th rune' stands for tip rune +// +// '4th rune' stands for empty 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 - refillAmount int64 - reverse bool - noBrackets bool + format [][]byte + tip []byte + refill int64 + reverse bool + flush func(w io.Writer, bb [][]byte) } -// NewBarFiller bar Filler used with *Progress.AddBar -func NewBarFiller() Filler { - filler := &barFiller{ - format: make([][]byte, utf8.RuneCountInString(defaultBarStyle)), +// NewBarFiller constucts mpb.Filler, to be used with *Progress.Add method. +func NewBarFiller(style string, reverse bool) Filler { + if style == "" { + style = DefaultBarStyle } - filler.setStyle(defaultBarStyle) - return filler + bf := &barFiller{ + format: make([][]byte, utf8.RuneCountInString(style)), + } + bf.SetStyle(style) + bf.SetReverse(reverse) + return bf } -func (s *barFiller) setStyle(style string) { +func (s *barFiller) SetStyle(style string) { if !utf8.ValidString(style) { return } @@ -45,23 +66,44 @@ src = append(src, []byte(string(r))) } copy(s.format, src) + if s.reverse { + s.tip = s.format[rRevTip] + } else { + s.tip = s.format[rTip] + } +} + +func (s *barFiller) SetReverse(reverse bool) { + if reverse { + s.tip = s.format[rRevTip] + s.flush = func(w io.Writer, bb [][]byte) { + for i := len(bb) - 1; i >= 0; i-- { + w.Write(bb[i]) + } + } + } else { + s.tip = s.format[rTip] + s.flush = func(w io.Writer, bb [][]byte) { + for i := 0; i < len(bb); i++ { + w.Write(bb[i]) + } + } + } + s.reverse = reverse } func (s *barFiller) SetRefill(amount int64) { - s.refillAmount = amount + s.refill = amount } func (s *barFiller) Fill(w io.Writer, width int, stat *decor.Statistics) { - - if !s.noBrackets { - // don't count rLeft and rRight as progress - width -= 2 - if width < 2 { - return - } - w.Write(s.format[rLeft]) - defer w.Write(s.format[rRight]) + // don't count rLeft and rRight as progress + width -= 2 + if width < 2 { + return } + w.Write(s.format[rLeft]) + defer w.Write(s.format[rRight]) bb := make([][]byte, width) @@ -71,12 +113,12 @@ bb[i] = s.format[rFill] } - if s.refillAmount > 0 { + if s.refill > 0 { var rwidth int - if s.refillAmount > stat.Current { + if s.refill > stat.Current { rwidth = cwidth } else { - rwidth = int(internal.PercentageRound(stat.Total, int64(s.refillAmount), width)) + rwidth = int(internal.PercentageRound(stat.Total, int64(s.refill), width)) } for i := 0; i < rwidth; i++ { bb[i] = s.format[rRefill] @@ -84,23 +126,12 @@ } if cwidth > 0 && cwidth < width { - bb[cwidth-1] = s.format[rTip] + bb[cwidth-1] = s.tip } for i := cwidth; i < width; i++ { bb[i] = s.format[rEmpty] } - if s.reverse { - if cwidth > 0 && cwidth < width { - bb[cwidth-1] = s.format[rRevTip] - } - for i := len(bb) - 1; i >= 0; i-- { - w.Write(bb[i]) - } - } else { - for i := 0; i < len(bb); i++ { - w.Write(bb[i]) - } - } + s.flush(w, bb) } diff --git a/bar_option.go b/bar_option.go index f8246e4..3f19527 100644 --- a/bar_option.go +++ b/bar_option.go @@ -130,50 +130,21 @@ } } -// BarStyle sets custom bar style, default one is "[=>-]<+". -// -// '[' left bracket rune -// -// '=' fill rune -// -// '>' tip rune -// -// '-' empty rune -// -// ']' right bracket rune -// -// '<' reverse tip rune, used when BarReverse option is set -// -// '+' refill rune, used when *Bar.SetRefill(int64) is called -// -// It's ok to provide first five runes only, for example BarStyle("╢▌▌░╟"). -// To omit left and right bracket runes, either set style as " =>- " -// or use BarNoBrackets option. +// BarStyle overrides mpb.DefaultBarStyle, for example BarStyle("╢▌▌░╟"). +// If you need to override `reverse tip` and `refill rune` set 6th and +// 7th rune respectively, for example BarStyle("[=>-]<+"). func BarStyle(style string) BarOption { - chk := func(filler Filler) (interface{}, bool) { - if style == "" { - return nil, false - } - t, ok := filler.(*barFiller) - return t, ok - } - cb := func(t interface{}) { - t.(*barFiller).setStyle(style) - } - return MakeFillerTypeSpecificBarOption(chk, cb) -} - -// BarNoBrackets omits left and right edge runes of the bar. Edges are -// brackets in default bar style, hence the name of the option. -func BarNoBrackets() BarOption { - chk := func(filler Filler) (interface{}, bool) { - t, ok := filler.(*barFiller) - return t, ok - } - cb := func(t interface{}) { - t.(*barFiller).noBrackets = true - } - return MakeFillerTypeSpecificBarOption(chk, cb) + if style == "" { + return nil + } + type styleSetter interface { + SetStyle(string) + } + return func(s *bState) { + if t, ok := s.filler.(styleSetter); ok { + t.SetStyle(style) + } + } } // BarNoPop disables bar pop out of container. Effective when @@ -186,14 +157,14 @@ // BarReverse reverse mode, bar will progress from right to left. func BarReverse() BarOption { - chk := func(filler Filler) (interface{}, bool) { - t, ok := filler.(*barFiller) - return t, ok - } - cb := func(t interface{}) { - t.(*barFiller).reverse = true - } - return MakeFillerTypeSpecificBarOption(chk, cb) + type revSetter interface { + SetReverse(bool) + } + return func(s *bState) { + if t, ok := s.filler.(revSetter); ok { + t.SetReverse(true) + } + } } // SpinnerStyle sets custom spinner style. diff --git a/draw_test.go b/draw_test.go index 9a3dff4..d8516b8 100644 --- a/draw_test.go +++ b/draw_test.go @@ -13,7 +13,7 @@ total, current int64 barWidth int trimSpace bool - noBrackets bool + reverse bool rup int64 want string }{ @@ -33,14 +33,6 @@ trimSpace: true, want: "", }, - { - name: "t,c,bw,noBrackets{60,20,80}", - total: 60, - current: 20, - barWidth: 80, - noBrackets: true, - want: "", - }, }, 1: { { @@ -58,14 +50,6 @@ trimSpace: true, want: "", }, - { - name: "t,c,bw,noBrackets{60,20,80}", - total: 60, - current: 20, - barWidth: 80, - noBrackets: true, - want: "", - }, }, 2: { { @@ -83,14 +67,6 @@ trimSpace: true, want: "", }, - { - name: "t,c,bw,noBrackets{60,20,80,true}", - total: 60, - current: 20, - barWidth: 80, - noBrackets: true, - want: " ", - }, }, 3: { { @@ -108,14 +84,6 @@ trimSpace: true, want: "", }, - { - name: "t,c,bw,trim{60,20,80,true}", - total: 60, - current: 20, - barWidth: 80, - noBrackets: true, - want: " - ", - }, }, 4: { { @@ -133,14 +101,6 @@ trimSpace: true, want: "[>-]", }, - { - name: "t,c,bw,noBrackets{60,20,80,true}", - total: 60, - current: 20, - barWidth: 80, - noBrackets: true, - want: " >- ", - }, }, 5: { { @@ -158,14 +118,6 @@ trimSpace: true, want: "[>--]", }, - { - name: "t,c,bw,noBrackets{60,20,80,true}", - total: 60, - current: 20, - barWidth: 80, - noBrackets: true, - want: " >-- ", - }, }, 6: { { @@ -183,14 +135,6 @@ trimSpace: true, want: "[>---]", }, - { - name: "t,c,bw,noBrackets{60,20,80,true}", - total: 60, - current: 20, - barWidth: 80, - noBrackets: true, - want: " >--- ", - }, }, 7: { { @@ -208,14 +152,6 @@ trimSpace: true, want: "[=>---]", }, - { - name: "t,c,bw,noBrackets{60,20,80,true}", - total: 60, - current: 20, - barWidth: 80, - noBrackets: true, - want: " =>--- ", - }, }, 8: { { @@ -233,14 +169,6 @@ trimSpace: true, want: "[=>----]", }, - { - name: "t,c,bw,noBrackets{60,20,80,true}", - total: 60, - current: 20, - barWidth: 80, - noBrackets: true, - want: " =>---- ", - }, }, 80: { { @@ -258,14 +186,6 @@ trimSpace: true, want: "[=========================>----------------------------------------------------]", }, - { - name: "t,c,bw,noBrackets{60,20,80,true}", - total: 60, - current: 20, - barWidth: 80, - noBrackets: true, - want: " =========================>---------------------------------------------------- ", - }, }, 100: { { @@ -312,6 +232,15 @@ barWidth: 100, trimSpace: true, want: "[===============================>------------------------------------------------------------------]", + }, + { + name: "t,c,bw,trim{100,33,100,true}", + total: 100, + current: 33, + barWidth: 100, + trimSpace: true, + reverse: true, + want: "[------------------------------------------------------------------<===============================]", }, { name: "t,c,bw,rup{100,33,100,33}", @@ -329,6 +258,16 @@ rup: 33, trimSpace: true, want: "[+++++++++++++++++++++++++++++++>------------------------------------------------------------------]", + }, + { + name: "t,c,bw,rup,trim{100,33,100,33,true}", + total: 100, + current: 33, + barWidth: 100, + rup: 33, + trimSpace: true, + reverse: true, + want: "[------------------------------------------------------------------<+++++++++++++++++++++++++++++++]", }, { name: "t,c,bw,rup{100,40,100,32}", @@ -383,12 +322,11 @@ var tmpBuf bytes.Buffer for termWidth, cases := range testSuite { for _, tc := range cases { - s := newTestState() + s := newTestState(tc.reverse) s.width = tc.barWidth s.total = tc.total s.current = tc.current s.trimSpace = tc.trimSpace - s.filler.(*barFiller).noBrackets = tc.noBrackets if tc.rup > 0 { if f, ok := s.filler.(interface{ SetRefill(int64) }); ok { f.SetRefill(tc.rup) @@ -411,9 +349,9 @@ } } -func newTestState() *bState { +func newTestState(reverse bool) *bState { s := &bState{ - filler: NewBarFiller(), + filler: NewBarFiller(DefaultBarStyle, reverse), bufP: new(bytes.Buffer), bufB: new(bytes.Buffer), bufA: new(bytes.Buffer), diff --git a/export_test.go b/export_test.go index 1d05eda..7f5cb84 100644 --- a/export_test.go +++ b/export_test.go @@ -1,6 +1,4 @@ package mpb -var ( - SyncWidth = syncWidth - DefaultBarStyle = defaultBarStyle -) +// make syncWidth func public in test +var SyncWidth = syncWidth diff --git a/progress.go b/progress.go index fad1054..db7d3e3 100644 --- a/progress.go +++ b/progress.go @@ -99,19 +99,19 @@ // AddBar creates a new progress bar and adds to the container. func (p *Progress) AddBar(total int64, options ...BarOption) *Bar { - return p.Add(total, NewBarFiller(), options...) + return p.Add(total, NewBarFiller(DefaultBarStyle, false), options...) } // AddSpinner creates a new spinner bar and adds to the container. func (p *Progress) AddSpinner(total int64, alignment SpinnerAlignment, options ...BarOption) *Bar { - return p.Add(total, NewSpinnerFiller(alignment), options...) + return p.Add(total, NewSpinnerFiller(DefaultSpinnerStyle, alignment), options...) } // Add creates a bar which renders itself by provided filler. // Set total to 0, if you plan to update it later. func (p *Progress) Add(total int64, filler Filler, options ...BarOption) *Bar { if filler == nil { - filler = NewBarFiller() + filler = NewBarFiller(DefaultBarStyle, false) } p.bwg.Add(1) result := make(chan *Bar) diff --git a/spinner_filler.go b/spinner_filler.go index 5353503..9f383fb 100644 --- a/spinner_filler.go +++ b/spinner_filler.go @@ -18,7 +18,8 @@ SpinnerOnRight ) -var defaultSpinnerStyle = []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"} +// DefaultSpinnerStyle is applied when bar constructed with *Progress.AddSpinner method. +var DefaultSpinnerStyle = []string{"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"} type spinnerFiller struct { frames []string @@ -26,10 +27,13 @@ alignment SpinnerAlignment } -// NewSpinnerFiller spinner Filler used with *Progress.AddSpinner -func NewSpinnerFiller(alignment SpinnerAlignment) Filler { +// NewSpinnerFiller constucts mpb.Filler, to be used with *Progress.Add method. +func NewSpinnerFiller(style []string, alignment SpinnerAlignment) Filler { + if len(style) == 0 { + style = DefaultSpinnerStyle + } filler := &spinnerFiller{ - frames: defaultSpinnerStyle, + frames: style, alignment: alignment, } return filler