summaryrefslogtreecommitdiff
path: root/vendor/github.com/vbauerster/mpb/decor/decorator.go
blob: 6aaf6c8307acdb5dd2b8362a54644990f120876b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package decor

import (
	"fmt"
	"time"
	"unicode/utf8"
)

const (
	// DidentRight bit specifies identation direction.
	// |foo   |b     | With DidentRight
	// |   foo|     b| Without DidentRight
	DidentRight = 1 << iota

	// DextraSpace bit adds extra space, makes sense with DSyncWidth only.
	// When DidentRight bit set, the space will be added to the right,
	// otherwise to the left.
	DextraSpace

	// DSyncWidth bit enables same column width synchronization.
	// Effective with multiple bars only.
	DSyncWidth

	// DSyncWidthR is shortcut for DSyncWidth|DidentRight
	DSyncWidthR = DSyncWidth | DidentRight

	// DSyncSpace is shortcut for DSyncWidth|DextraSpace
	DSyncSpace = DSyncWidth | DextraSpace

	// DSyncSpaceR is shortcut for DSyncWidth|DextraSpace|DidentRight
	DSyncSpaceR = DSyncWidth | DextraSpace | DidentRight
)

const (
	ET_STYLE_GO = iota
	ET_STYLE_HHMMSS
	ET_STYLE_HHMM
	ET_STYLE_MMSS
)

// Statistics is a struct, which gets passed to a Decorator.
type Statistics struct {
	ID        int
	Completed bool
	Total     int64
	Current   int64
}

// Decorator interface.
// A decorator must implement this interface, in order to be used with mpb library.
type Decorator interface {
	Decor(*Statistics) string
	Syncable
}

// Syncable interface.
// All decorators implement this interface implicitly.
// Its Syncable method exposes width sync channel, if sync is enabled.
type Syncable interface {
	Syncable() (bool, chan int)
}

// OnCompleteMessenger interface.
// Decorators implementing this interface suppose to return provided string on complete event.
type OnCompleteMessenger interface {
	OnCompleteMessage(string)
}

// AmountReceiver interface.
// If decorator needs to receive increment amount,
// so this is the right interface to implement.
type AmountReceiver interface {
	NextAmount(int, ...time.Duration)
}

// ShutdownListener interface.
// If decorator needs to be notified once upon bar shutdown event,
// so this is the right interface to implement.
type ShutdownListener interface {
	Shutdown()
}

// Global convenience shortcuts
var (
	WCSyncWidth  = WC{C: DSyncWidth}
	WCSyncWidthR = WC{C: DSyncWidthR}
	WCSyncSpace  = WC{C: DSyncSpace}
	WCSyncSpaceR = WC{C: DSyncSpaceR}
)

// WC is a struct with two public fields W and C, both of int type.
// W represents width and C represents bit set of width related config.
type WC struct {
	W      int
	C      int
	format string
	wsync  chan int
}

// 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 {
	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++
		}
		return fmt.Sprintf(fmt.Sprintf(wc.format, max), msg)
	}
	return fmt.Sprintf(fmt.Sprintf(wc.format, wc.W), msg)
}

// Init initializes width related config.
func (wc *WC) Init() {
	wc.format = "%%"
	if (wc.C & DidentRight) != 0 {
		wc.format += "-"
	}
	wc.format += "%ds"
	if (wc.C & DSyncWidth) != 0 {
		wc.wsync = make(chan int)
	}
}

func (wc *WC) Syncable() (bool, chan int) {
	return (wc.C & DSyncWidth) != 0, wc.wsync
}

// OnComplete returns decorator, which wraps provided decorator, with sole
// purpose to display provided message on complete event.
//
//	`decorator` Decorator to wrap
//
//	`message` message to display on complete event
func OnComplete(decorator Decorator, message string) Decorator {
	if d, ok := decorator.(OnCompleteMessenger); ok {
		d.OnCompleteMessage(message)
	}
	return decorator
}