diff --git a/bar.go b/bar.go index 115f1bb..ba2d8d2 100644 --- a/bar.go +++ b/bar.go @@ -18,8 +18,7 @@ leftEnd byte rightEnd byte - lastFrame []byte - lastStatus int + trimLeftSpace, trimRightSpace bool incrCh chan int redrawReqCh chan *redrawRequest @@ -38,7 +37,7 @@ TimeElapsed, TimePerItemEstimate time.Duration } -func (s *Statistics) eta() time.Duration { +func (s *Statistics) Eta() time.Duration { return time.Duration(s.Total-s.Current) * s.TimePerItemEstimate } @@ -67,10 +66,20 @@ // SetWidth sets width of the bar func (b *Bar) SetWidth(n int) *Bar { - if n <= 0 { + if n < 2 { return b } b.width = n + return b +} + +func (b *Bar) TrimLeftSpace() *Bar { + b.trimLeftSpace = true + return b +} + +func (b *Bar) TrimRightSpace() *Bar { + b.trimRightSpace = true return b } @@ -129,11 +138,7 @@ } // Current returns the actual current. -// If bar was stopped by Stop(), subsequent calls to Current will return -1 func (b *Bar) Current() int { - if b.isDone() { - return -1 - } respCh := make(chan int) b.currentReqCh <- respCh return <-respCh @@ -164,24 +169,14 @@ return b } -// String returns the string representation of the bar -// func (b *Bar) String() string { -// if b.isDone() { -// return string(b.lastFrame) -// } -// respCh := make(chan []byte) -// b.redrawReqCh <- respCh -// return string(<-respCh) -// } - type redrawRequest struct { width int respCh chan []byte } func (b *Bar) Bytes(width int) []byte { - if b.isDone() { - return b.lastFrame + if width <= 0 { + width = b.width } respCh := make(chan []byte) b.redrawReqCh <- &redrawRequest{width, respCh} @@ -191,7 +186,6 @@ func (b *Bar) server(wg *sync.WaitGroup, total int) { timeStarted := time.Now() blockStartTime := timeStarted - // buf := make([]byte, 0, b.width+32) var tpie time.Duration var timeElapsed time.Duration var appendFuncs []DecoratorFunc @@ -232,19 +226,14 @@ respCh <- percentage(total, current, 100) case <-b.flushedCh: if completed && !b.isDone() { - stat := &Statistics{total, current, termWidth, timeElapsed, tpie} - b.lastFrame = b.draw(stat, appendFuncs, prependFuncs) - b.lastStatus = percentage(total, current, 100) close(b.done) wg.Done() - return } case <-b.stopCh: close(b.done) if !completed { wg.Done() } - return } } } @@ -270,14 +259,25 @@ prependCount := utf8.RuneCount(prependBlock) barCount := utf8.RuneCount(barBlock) appendCount := utf8.RuneCount(appendBlock) + + var leftSpace, rightSpace []byte + space := []byte{' '} + if !b.trimLeftSpace { + prependCount++ + leftSpace = space + } + if !b.trimRightSpace { + appendCount++ + rightSpace = space + } + totalCount := prependCount + barCount + appendCount - if totalCount >= stat.TermWidth { newWidth := stat.TermWidth - prependCount - appendCount barBlock = b.fillBar(stat.Total, stat.Current, newWidth-1) } - for _, block := range [...][]byte{prependBlock, barBlock, appendBlock} { + for _, block := range [...][]byte{prependBlock, leftSpace, barBlock, rightSpace, appendBlock} { buf = append(buf, block...) } @@ -288,6 +288,7 @@ if width < 2 { return []byte{b.leftEnd, b.rightEnd} } + buf := make([]byte, width) completedWidth := percentage(total, current, width) @@ -303,6 +304,7 @@ } // set left and right ends bits buf[0], buf[width-1] = b.leftEnd, b.rightEnd + return buf } @@ -316,9 +318,6 @@ } func (b *Bar) status() int { - if b.isDone() { - return b.lastStatus - } respCh := make(chan int) b.statusReqCh <- respCh return <-respCh diff --git a/cwriter/writer_posix.go b/cwriter/writer_posix.go index 4c3058d..6a08d6c 100644 --- a/cwriter/writer_posix.go +++ b/cwriter/writer_posix.go @@ -30,13 +30,13 @@ func TerminalWidth() (int, error) { w := new(window) tio := syscall.TIOCGWINSZ - res, _, err := syscall.Syscall(syscall.SYS_IOCTL, + _, _, errno := syscall.Syscall(syscall.SYS_IOCTL, tty.Fd(), uintptr(tio), uintptr(unsafe.Pointer(w)), ) - if int(res) == -1 { - return 0, err + if errno != 0 { + return 0, errno } return int(w.Col), nil } diff --git a/decorators.go b/decorators.go index bda0023..39aaa9d 100644 --- a/decorators.go +++ b/decorators.go @@ -43,14 +43,14 @@ func (b *Bar) PrependETA(padding int) *Bar { layout := "ETA%" + strconv.Itoa(padding) + "s" b.PrependFunc(func(s *Statistics) string { - return fmt.Sprintf(layout, time.Duration(s.eta().Seconds())*time.Second) + return fmt.Sprintf(layout, time.Duration(s.Eta().Seconds())*time.Second) }) return b } func (b *Bar) AppendETA() *Bar { b.AppendFunc(func(s *Statistics) string { - return fmt.Sprintf("ETA %s", time.Duration(s.eta().Seconds())*time.Second) + return fmt.Sprintf("ETA %s", time.Duration(s.Eta().Seconds())*time.Second) }) return b } diff --git a/example/interrupt/main.go b/example/interrupt/main.go index 9051f00..e875d0c 100644 --- a/example/interrupt/main.go +++ b/example/interrupt/main.go @@ -26,8 +26,8 @@ for i := 0; bar.InProgress(); i++ { time.Sleep(time.Duration(blockSize) * (50*time.Millisecond + time.Duration(rand.Intn(5*int(time.Millisecond))))) bar.Incr(blockSize) - if bar.Current() > 42 { - p.RemoveBar(bar) + if bar.Current() > 42 && p.RemoveBar(bar) { + break } blockSize = rand.Intn(maxBlockSize) + 1 } diff --git a/example/prependETA/main.go b/example/prependETA/main.go index d242813..8f67483 100644 --- a/example/prependETA/main.go +++ b/example/prependETA/main.go @@ -40,6 +40,9 @@ for i := 0; i < 100; i++ { time.Sleep(time.Duration(blockSize) * (50*time.Millisecond + time.Duration(rand.Intn(5*int(time.Millisecond))))) bar2.Incr(1) + if bar2.Current() > 42 && p.RemoveBar(bar2) { + break + } blockSize = rand.Intn(maxBlockSize) + 1 } }() diff --git a/example/prependElapsed/main.go b/example/prependElapsed/main.go index 9bd9079..291cec7 100644 --- a/example/prependElapsed/main.go +++ b/example/prependElapsed/main.go @@ -19,8 +19,10 @@ p := mpb.New().SetWidth(64) // p := mpb.New().RefreshRate(80 * time.Millisecond).SetWidth(64) - name1 := "Bar#1:" - bar1 := p.AddBar(50).AppendPercentage().PrependElapsed(3).PrependName(name1, len(name1)) + name1 := "Bar#1: " + bar1 := p.AddBar(50). + PrependName(name1, len(name1)).PrependElapsed(3). + AppendPercentage().TrimRightSpace() wg.Add(1) go func() { defer wg.Done() @@ -32,7 +34,9 @@ } }() - bar2 := p.AddBar(100).AppendPercentage().PrependElapsed(3).PrependName("", 0-len(name1)) + bar2 := p.AddBar(100). + PrependName("", 0-len(name1)).PrependElapsed(3). + AppendPercentage().TrimRightSpace() wg.Add(1) go func() { defer wg.Done() @@ -44,7 +48,9 @@ } }() - bar3 := p.AddBar(80).AppendPercentage().PrependElapsed(3).PrependName("Bar#3:", 0) + bar3 := p.AddBar(80). + PrependName("Bar#3: ", 0).PrependElapsed(3). + AppendPercentage().TrimRightSpace() wg.Add(1) go func() { defer wg.Done() diff --git a/example/remove/main.go b/example/remove/main.go index 8711571..a9c372f 100644 --- a/example/remove/main.go +++ b/example/remove/main.go @@ -19,8 +19,10 @@ p := mpb.New().SetWidth(64) // p := mpb.New().RefreshRate(100 * time.Millisecond).SetWidth(64) - name1 := "Bar#1:" - bar1 := p.AddBar(50).AppendETA().PrependPercentage(3).PrependName(name1, len(name1)) + name1 := "Bar#1: " + bar1 := p.AddBar(50). + PrependName(name1, len(name1)).PrependETA(4). + AppendPercentage().TrimRightSpace() wg.Add(1) go func() { defer wg.Done() @@ -32,7 +34,9 @@ } }() - bar2 := p.AddBar(100).AppendETA().PrependPercentage(3).PrependName("", 0-len(name1)) + bar2 := p.AddBar(100). + PrependName("", 0-len(name1)).PrependETA(4). + AppendPercentage().TrimRightSpace() wg.Add(1) go func() { defer wg.Done() @@ -40,11 +44,16 @@ for i := 0; i < 100; i++ { time.Sleep(time.Duration(blockSize) * (50*time.Millisecond + time.Duration(rand.Intn(5*int(time.Millisecond))))) bar2.Incr(1) + if bar2.Current() > 42 && p.RemoveBar(bar2) { + break + } blockSize = rand.Intn(maxBlockSize) + 1 } }() - bar3 := p.AddBar(80).AppendETA().PrependPercentage(3).PrependName("Bar#3:", 0) + bar3 := p.AddBar(80). + PrependName("Bar#3: ", 0).PrependETA(4). + AppendPercentage().TrimRightSpace() wg.Add(1) go func() { defer wg.Done() @@ -56,13 +65,8 @@ } }() - time.Sleep(3 * time.Second) - // After removing the bar, it is good practice to ask underlying goroutine - // (2nd one in our example) to stop, so its wg.Done() will execute in time - p.RemoveBar(bar2) - wg.Wait() p.Stop() - // p.AddBar(1) // panic: you cannot reuse p, create new one! + // p.AddBar(2) // panic: you cannot reuse p, create new one! fmt.Println("stop") } diff --git a/progress.go b/progress.go index da4d5e3..0a909a8 100644 --- a/progress.go +++ b/progress.go @@ -185,7 +185,6 @@ respCh <- len(bars) case <-t.C: width, _ := cwriter.TerminalWidth() - // fmt.Fprintf(os.Stderr, "twidth: %d\n", width) switch p.sort { case SortTop: sort.Sort(sort.Reverse(SortableBarSlice(bars))) @@ -193,7 +192,6 @@ sort.Sort(SortableBarSlice(bars)) } for _, b := range bars { - // fmt.Fprintln(cw, b) buf := b.Bytes(width) buf = append(buf, '\n') cw.Write(buf)