diff --git a/bar.go b/bar.go index d629e78..598a92b 100644 --- a/bar.go +++ b/bar.go @@ -396,6 +396,18 @@ return table } +func (s *bState) appendAmountReceiver(d decor.Decorator) { + if ar, ok := d.(decor.AmountReceiver); ok { + s.amountReceivers = append(s.amountReceivers, ar) + } +} + +func (s *bState) appendShutdownListener(d decor.Decorator) { + if sl, ok := d.(decor.ShutdownListener); ok { + s.shutdownListeners = append(s.shutdownListeners, sl) + } +} + func (b *Bar) refreshNowTillShutdown() { for { select { diff --git a/bar_option.go b/bar_option.go index 9ee3209..26d72e4 100644 --- a/bar_option.go +++ b/bar_option.go @@ -11,11 +11,12 @@ func AppendDecorators(appenders ...decor.Decorator) BarOption { return func(s *bState) { for _, decorator := range appenders { - if ar, ok := decorator.(decor.AmountReceiver); ok { - s.amountReceivers = append(s.amountReceivers, ar) - } - if sl, ok := decorator.(decor.ShutdownListener); ok { - s.shutdownListeners = append(s.shutdownListeners, sl) + s.appendAmountReceiver(decorator) + s.appendShutdownListener(decorator) + if md, ok := decorator.(*decor.MergeDecorator); ok { + s.appendAmountReceiver(md.Decorator) + s.appendShutdownListener(md.Decorator) + s.aDecorators = append(s.aDecorators, md.PlaceHolders()...) } s.aDecorators = append(s.aDecorators, decorator) } @@ -26,11 +27,12 @@ func PrependDecorators(prependers ...decor.Decorator) BarOption { return func(s *bState) { for _, decorator := range prependers { - if ar, ok := decorator.(decor.AmountReceiver); ok { - s.amountReceivers = append(s.amountReceivers, ar) - } - if sl, ok := decorator.(decor.ShutdownListener); ok { - s.shutdownListeners = append(s.shutdownListeners, sl) + s.appendAmountReceiver(decorator) + s.appendShutdownListener(decorator) + if md, ok := decorator.(*decor.MergeDecorator); ok { + s.appendAmountReceiver(md.Decorator) + s.appendShutdownListener(md.Decorator) + s.pDecorators = append(s.pDecorators, md.PlaceHolders()...) } s.pDecorators = append(s.pDecorators, decorator) } diff --git a/decor/decorator.go b/decor/decorator.go index fa7c994..2f73263 100644 --- a/decor/decorator.go +++ b/decor/decorator.go @@ -55,15 +55,21 @@ // A decorator must implement this interface, in order to be used with // mpb library. type Decorator interface { + ConfigSetter Synchronizer Decor(*Statistics) string } // Synchronizer interface. // All decorators implement this interface implicitly. Its Sync -// method exposes width sync channel, if sync is enabled. +// method exposes width sync channel, if DSyncWidth bit is set. type Synchronizer interface { Sync() (chan int, bool) +} + +// ConfigSetter interface +type ConfigSetter interface { + SetConfig(config WC) (old WC) } // OnCompleteMessenger interface. @@ -107,13 +113,10 @@ // FormatMsg formats final message according to WC.W and WC.C. // Should be called by any Decorator implementation. -func (wc WC) FormatMsg(msg string) string { +func (wc *WC) FormatMsg(msg string) string { if (wc.C & DSyncWidth) != 0 { wc.wsync <- utf8.RuneCountInString(msg) max := <-wc.wsync - if max == 0 { - max = wc.W - } if (wc.C & DextraSpace) != 0 { max++ } @@ -139,6 +142,13 @@ return wc.wsync, (wc.C & DSyncWidth) != 0 } +func (wc *WC) SetConfig(conf WC) (old WC) { + old = *wc + *wc = conf + wc.Init() + return old +} + // OnComplete returns decorator, which wraps provided decorator, with // sole purpose to display provided message on complete event. // diff --git a/decor/merge.go b/decor/merge.go index 92c070a..e16108c 100644 --- a/decor/merge.go +++ b/decor/merge.go @@ -6,29 +6,33 @@ "unicode/utf8" ) -func Merge(decorator Decorator, wcc ...WC) Decorator { +// Merge helper func, provides a way to synchronize width of single +// decorator with adjacent decorators of different bar, like so: +// +--------+---------+ +// | MERGE(D) | +// +--------+---------+ +// | D1 | D2 | +// +--------+---------+ +// +func Merge(decorator Decorator, placeholders ...WC) Decorator { if _, ok := decorator.Sync(); !ok { return decorator } - var placeHolders []*placeHolderDecorator - for _, wc := range wcc { + md := &MergeDecorator{Decorator: decorator} + md.wc = decorator.SetConfig(md.wc) + for _, wc := range placeholders { wc.Init() - placeHolders = append(placeHolders, &placeHolderDecorator{ + md.placeHolders = append(md.placeHolders, &placeHolderDecorator{ WC: wc, wsync: make(chan int), }) } - md := &MergeDecorator{ - decorator: decorator, - placeHolders: placeHolders, - } - md.WC = decorator.SetConfig(md.WC) return md } type MergeDecorator struct { - WC - decorator Decorator + Decorator + wc WC placeHolders []*placeHolderDecorator } @@ -40,24 +44,27 @@ return decorators } +func (md *MergeDecorator) Sync() (chan int, bool) { + return md.wc.Sync() +} + func (d *MergeDecorator) Decor(st *Statistics) string { - msg := d.decorator.Decor(st) + msg := d.Decorator.Decor(st) msgLen := utf8.RuneCountInString(msg) pWidth := msgLen / (len(d.placeHolders) + 1) mod := msgLen % (len(d.placeHolders) + 1) - d.wsync <- pWidth + mod + d.wc.wsync <- pWidth + mod for _, ph := range d.placeHolders { ph.wsync <- pWidth } - // fmt.Fprintln(os.Stderr, "all sent") - max := <-d.wsync + max := <-d.wc.wsync for _, ph := range d.placeHolders { max += <-ph.wsync } - if (d.C & DextraSpace) != 0 { + if (d.wc.C & DextraSpace) != 0 { max++ } - return fmt.Sprintf(fmt.Sprintf(d.format, max), msg) + return fmt.Sprintf(fmt.Sprintf(d.wc.format, max), msg) } type placeHolderDecorator struct {