File: decorator.go

package info (click to toggle)
golang-github-vbauerster-mpb 8.8.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 1,044 kB
  • sloc: sh: 7; makefile: 3
file content (183 lines) | stat: -rw-r--r-- 5,008 bytes parent folder | download
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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package decor

import (
	"fmt"
	"time"

	"github.com/mattn/go-runewidth"
)

const (
	// DindentRight sets indentation from right to left.
	//
	//	|foo   |b     | DindentRight is set
	//	|   foo|     b| DindentRight is not set
	DindentRight = 1 << iota

	// DextraSpace bit adds extra indentation space.
	DextraSpace

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

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

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

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

// TimeStyle enum.
type TimeStyle int

// TimeStyle kinds.
const (
	ET_STYLE_GO TimeStyle = iota
	ET_STYLE_HHMMSS
	ET_STYLE_HHMM
	ET_STYLE_MMSS
)

// Statistics contains fields which are necessary for implementing
// `decor.Decorator` and `mpb.BarFiller` interfaces.
type Statistics struct {
	AvailableWidth int // calculated width initially equal to terminal width
	RequestedWidth int // width set by `mpb.WithWidth`
	ID             int
	Total          int64
	Current        int64
	Refill         int64
	Completed      bool
	Aborted        bool
}

// Decorator interface.
// Most of the time there is no need to implement this interface
// manually, as decor package already provides a wide range of decorators
// which implement this interface. If however built-in decorators don't
// meet your needs, you're free to implement your own one by implementing
// this particular interface. The easy way to go is to convert a
// `DecorFunc` into a `Decorator` interface by using provided
// `func Any(DecorFunc, ...WC) Decorator`.
type Decorator interface {
	Synchronizer
	Formatter
	Decor(Statistics) (str string, viewWidth int)
}

// DecorFunc func type.
// To be used with `func Any(DecorFunc, ...WC) Decorator`.
type DecorFunc func(Statistics) string

// Synchronizer interface.
// All decorators implement this interface implicitly. Its Sync
// method exposes width sync channel, if DSyncWidth bit is set.
type Synchronizer interface {
	Sync() (chan int, bool)
}

// Formatter interface.
// Format method needs to be called from within Decorator.Decor method
// in order to format string according to decor.WC settings.
// No need to implement manually as long as decor.WC is embedded.
type Formatter interface {
	Format(string) (_ string, width int)
}

// Wrapper interface.
// If you're implementing custom Decorator by wrapping a built-in one,
// it is necessary to implement this interface to retain functionality
// of built-in Decorator.
type Wrapper interface {
	Unwrap() Decorator
}

// EwmaDecorator interface.
// EWMA based decorators should implement this one.
type EwmaDecorator interface {
	EwmaUpdate(int64, time.Duration)
}

// AverageDecorator interface.
// Average decorators should implement this interface to provide start
// time adjustment facility, for resume-able tasks.
type AverageDecorator interface {
	AverageAdjust(time.Time)
}

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

// Global convenience instances of WC with sync width bit set.
// To be used with multiple bars only, i.e. not effective for single bar usage.
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.
// A decorator should embed WC, to enable width synchronization.
type WC struct {
	W     int
	C     int
	fill  func(s string, w int) string
	wsync chan int
}

// Format should be called by any Decorator implementation.
// Returns formatted string and its view (visual) width.
func (wc WC) Format(str string) (string, int) {
	width := runewidth.StringWidth(str)
	if wc.W > width {
		width = wc.W
	} else if (wc.C & DextraSpace) != 0 {
		width++
	}
	if (wc.C & DSyncWidth) != 0 {
		wc.wsync <- width
		width = <-wc.wsync
	}
	return wc.fill(str, width), width
}

// Init initializes width related config.
func (wc *WC) Init() WC {
	if (wc.C & DindentRight) != 0 {
		wc.fill = runewidth.FillRight
	} else {
		wc.fill = runewidth.FillLeft
	}
	if (wc.C & DSyncWidth) != 0 {
		// it's deliberate choice to override wsync on each Init() call,
		// this way globals like WCSyncSpace can be reused
		wc.wsync = make(chan int)
	}
	return *wc
}

// Sync is implementation of Synchronizer interface.
func (wc WC) Sync() (chan int, bool) {
	if (wc.C&DSyncWidth) != 0 && wc.wsync == nil {
		panic(fmt.Sprintf("%T is not initialized", wc))
	}
	return wc.wsync, (wc.C & DSyncWidth) != 0
}

func initWC(wcc ...WC) WC {
	var wc WC
	for _, nwc := range wcc {
		wc = nwc
	}
	return wc.Init()
}