Codebase list golang-github-vbauerster-mpb / ff13621
use go-runewidth Vladimir Bauer 6 years ago
6 changed file(s) with 104 addition(s) and 68 deletion(s). Raw diff Collapse all Expand all
77 "log"
88 "strings"
99 "time"
10 "unicode/utf8"
1110
1211 "github.com/acarl005/stripansi"
12 "github.com/mattn/go-runewidth"
1313 "github.com/vbauerster/mpb/v5/decor"
1414 )
1515
386386 func (s *bState) draw(stat decor.Statistics) io.Reader {
387387 for _, d := range s.pDecorators {
388388 str := d.Decor(stat)
389 stat.OccupiedWidth += utf8.RuneCountInString(stripansi.Strip(str))
389 stat.OccupiedWidth += runewidth.StringWidth(stripansi.Strip(str))
390390 s.bufP.WriteString(str)
391391 }
392392
393393 for _, d := range s.aDecorators {
394394 str := d.Decor(stat)
395 stat.OccupiedWidth += utf8.RuneCountInString(stripansi.Strip(str))
395 stat.OccupiedWidth += runewidth.StringWidth(stripansi.Strip(str))
396396 s.bufA.WriteString(str)
397397 }
398398
33 "io"
44 "unicode/utf8"
55
6 "github.com/mattn/go-runewidth"
67 "github.com/vbauerster/mpb/v5/decor"
78 "github.com/vbauerster/mpb/v5/internal"
89 )
1112 rLeft = iota
1213 rFill
1314 rTip
14 rEmpty
15 rSpace
1516 rRight
1617 rRevTip
1718 rRefill
2627 //
2728 // '3rd rune' stands for tip rune
2829 //
29 // '4th rune' stands for empty rune
30 // '4th rune' stands for space rune
3031 //
3132 // '5th rune' stands for right boundary rune
3233 //
3839
3940 type barFiller struct {
4041 format [][]byte
42 rwidth []int
4143 tip []byte
4244 refill int64
4345 reverse bool
44 flush func(w io.Writer, bb [][]byte)
46 flush func(io.Writer, *space, [][]byte)
47 }
48
49 type space struct {
50 space []byte
51 width int
52 count int
4553 }
4654
4755 // NewBarFiller constucts mpb.BarFiller, to be used with *Progress.Add(...) *Bar method.
4856 func NewBarFiller(style string, reverse bool) BarFiller {
49 if style == "" {
50 style = DefaultBarStyle
51 }
5257 bf := &barFiller{
53 format: make([][]byte, utf8.RuneCountInString(style)),
58 format: make([][]byte, len(DefaultBarStyle)),
59 rwidth: make([]int, len(DefaultBarStyle)),
5460 reverse: reverse,
5561 }
5662 bf.SetStyle(style)
6167 if !utf8.ValidString(style) {
6268 return
6369 }
64 src := make([][]byte, 0, utf8.RuneCountInString(style))
70 if style == "" {
71 style = DefaultBarStyle
72 }
73 src := make([][]byte, utf8.RuneCountInString(style))
74 i := 0
6575 for _, r := range style {
66 src = append(src, []byte(string(r)))
76 s.rwidth[i] = runewidth.RuneWidth(r)
77 src[i] = []byte(string(r))
78 i++
6779 }
6880 copy(s.format, src)
6981 s.SetReverse(s.reverse)
8799 func (s *barFiller) Fill(w io.Writer, reqWidth int, stat decor.Statistics) {
88100 width := internal.CalcWidthForBarFiller(reqWidth, stat.TermWidth-stat.OccupiedWidth)
89101
90 width -= 2 // don't count rLeft and rRight as progress
91 if width < 2 {
102 // don't count rLeft and rRight as progress
103 brackets := s.rwidth[rLeft] + s.rwidth[rRight]
104 width -= brackets
105 if width < brackets {
92106 return
93107 }
94108 w.Write(s.format[rLeft])
95109 defer w.Write(s.format[rRight])
96110
97 bb := make([][]byte, width)
98
99111 cwidth := int(internal.PercentageRound(stat.Total, stat.Current, width))
100
101 for i := 0; i < cwidth; i++ {
102 bb[i] = s.format[rFill]
112 bb := make([][]byte, cwidth)
113 space := &space{
114 space: s.format[rSpace],
115 width: s.rwidth[rSpace],
116 count: width - cwidth,
117 }
118 if cwidth == 0 {
119 s.flush(w, space, bb)
120 return
103121 }
104122
123 index := 0
124 if space.count != 0 {
125 bb[index] = s.tip
126 cwidth -= s.rwidth[rTip]
127 } else {
128 bb[index] = s.format[rFill]
129 cwidth -= s.rwidth[rFill]
130 }
131 index++
132
133 rwidth := 0
105134 if s.refill > 0 {
106 var rwidth int
107 if s.refill > stat.Current {
108 rwidth = cwidth
109 } else {
135 rwidth = cwidth
136 if s.refill < stat.Current {
110137 rwidth = int(internal.PercentageRound(stat.Total, int64(s.refill), width))
111138 }
112 for i := 0; i < rwidth; i++ {
113 bb[i] = s.format[rRefill]
114 }
139 cwidth -= rwidth
115140 }
116141
117 if cwidth > 0 && cwidth < width {
118 bb[cwidth-1] = s.tip
142 for cwidth > 0 {
143 bb[index] = s.format[rFill]
144 cwidth -= s.rwidth[rFill]
145 index++
119146 }
120147
121 for i := cwidth; i < width; i++ {
122 bb[i] = s.format[rEmpty]
148 for rwidth > 0 {
149 bb[index] = s.format[rRefill]
150 rwidth -= s.rwidth[rRefill]
151 index++
123152 }
124153
125 s.flush(w, bb)
154 s.flush(w, space, bb)
126155 }
127156
128 func regularFlush(w io.Writer, bb [][]byte) {
157 func regularFlush(w io.Writer, space *space, bb [][]byte) {
158 for i := len(bb) - 1; i >= 0; i-- {
159 w.Write(bb[i])
160 }
161 for space.count > 0 {
162 w.Write(space.space)
163 space.count -= space.width
164 }
165 }
166
167 func reverseFlush(w io.Writer, space *space, bb [][]byte) {
168 for space.count > 0 {
169 w.Write(space.space)
170 space.count -= space.width
171 }
129172 for i := 0; i < len(bb); i++ {
130173 w.Write(bb[i])
131174 }
132175 }
133
134 func reverseFlush(w io.Writer, bb [][]byte) {
135 for i := len(bb) - 1; i >= 0; i-- {
136 w.Write(bb[i])
137 }
138 }
22 import (
33 "fmt"
44 "time"
5 "unicode/utf8"
65
76 "github.com/acarl005/stripansi"
7 "github.com/mattn/go-runewidth"
88 )
99
1010 const (
126126 // W represents width and C represents bit set of width related config.
127127 // A decorator should embed WC, to enable width synchronization.
128128 type WC struct {
129 W int
130 C int
131 dynFormat string
132 wsync chan int
129 W int
130 C int
131 fill func(s string, w int) string
132 wsync chan int
133133 }
134134
135135 // FormatMsg formats final message according to WC.W and WC.C.
136136 // Should be called by any Decorator implementation.
137137 func (wc *WC) FormatMsg(msg string) string {
138 var format string
139 runeCount := utf8.RuneCountInString(stripansi.Strip(msg))
140 ansiCount := utf8.RuneCountInString(msg) - runeCount
138 pureWidth := runewidth.StringWidth(msg)
139 stripWidth := runewidth.StringWidth(stripansi.Strip(msg))
140 maxCell := wc.W
141141 if (wc.C & DSyncWidth) != 0 {
142 cellCount := stripWidth
142143 if (wc.C & DextraSpace) != 0 {
143 runeCount++
144 cellCount++
144145 }
145 wc.wsync <- runeCount
146 max := <-wc.wsync
147 format = fmt.Sprintf(wc.dynFormat, ansiCount+max)
148 } else {
149 format = fmt.Sprintf(wc.dynFormat, ansiCount+wc.W)
146 wc.wsync <- cellCount
147 maxCell = <-wc.wsync
150148 }
151 return fmt.Sprintf(format, msg)
149 return wc.fill(msg, maxCell+(pureWidth-stripWidth))
152150 }
153151
154152 // Init initializes width related config.
155153 func (wc *WC) Init() WC {
156 wc.dynFormat = "%%"
154 wc.fill = runewidth.FillLeft
157155 if (wc.C & DidentRight) != 0 {
158 wc.dynFormat += "-"
156 wc.fill = runewidth.FillRight
159157 }
160 wc.dynFormat += "%ds"
161158 if (wc.C & DSyncWidth) != 0 {
162159 // it's deliberate choice to override wsync on each Init() call,
163160 // this way globals like WCSyncSpace can be reused
00 package decor
11
22 import (
3 "fmt"
43 "strings"
5 "unicode/utf8"
64
75 "github.com/acarl005/stripansi"
6 "github.com/mattn/go-runewidth"
87 )
98
109 // Merge wraps its decorator argument with intention to sync width
6766
6867 func (d *mergeDecorator) Decor(s Statistics) string {
6968 msg := d.Decorator.Decor(s)
70 msgLen := utf8.RuneCountInString(stripansi.Strip(msg))
69 pureWidth := runewidth.StringWidth(msg)
70 stripWidth := runewidth.StringWidth(stripansi.Strip(msg))
71 cellCount := stripWidth
7172 if (d.wc.C & DextraSpace) != 0 {
72 msgLen++
73 cellCount++
7374 }
7475
75 var total int
76 max := utf8.RuneCountInString(d.placeHolders[0].FormatMsg(""))
77 total += max
78 pw := (msgLen - max) / len(d.placeHolders)
79 rem := (msgLen - max) % len(d.placeHolders)
76 total := runewidth.StringWidth(d.placeHolders[0].FormatMsg(""))
77 pw := (cellCount - total) / len(d.placeHolders)
78 rem := (cellCount - total) % len(d.placeHolders)
8079
8180 var diff int
8281 for i := 1; i < len(d.placeHolders); i++ {
8887 width = 0
8988 }
9089 }
91 max = utf8.RuneCountInString(ph.FormatMsg(strings.Repeat(" ", width)))
90 max := runewidth.StringWidth(ph.FormatMsg(strings.Repeat(" ", width)))
9291 total += max
9392 diff = max - pw
9493 }
9594
9695 d.wc.wsync <- pw + rem
97 max = <-d.wc.wsync
98 return fmt.Sprintf(fmt.Sprintf(d.wc.dynFormat, max+total), msg)
96 max := <-d.wc.wsync
97 return d.wc.fill(msg, max+total+(pureWidth-stripWidth))
9998 }
10099
101100 type placeHolderDecorator struct {
33 github.com/VividCortex/ewma v1.1.1
44 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d
55 github.com/mattn/go-isatty v0.0.12
6 github.com/mattn/go-runewidth v0.0.9
67 golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f
78 )
89
33 github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo=
44 github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
55 github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
6 github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
7 github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
68 golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
79 golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f h1:mOhmO9WsBaJCNmaZHPtHs9wOcdqdKCjF6OPJlmDM3KI=
810 golang.org/x/sys v0.0.0-20200509044756-6aff5f38e54f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=