diff --git a/bar.go b/bar.go index cf9413e..37850a4 100644 --- a/bar.go +++ b/bar.go @@ -3,9 +3,7 @@ import ( "bytes" "context" - "fmt" "io" - "runtime/debug" "strings" "sync" "time" @@ -27,7 +25,7 @@ cancel func() } -type extenderFunc func(rows []io.Reader, stat decor.Statistics) []io.Reader +type extenderFunc func([]io.Reader, decor.Statistics) ([]io.Reader, error) // bState is actual bar's state. type bState struct { @@ -63,9 +61,9 @@ } type renderFrame struct { - rows []io.Reader - recovered bool - shutdown int + rows []io.Reader + shutdown int + err error } func newBar(container *Progress, bs *bState) *Bar { @@ -378,43 +376,25 @@ fn := func(s *bState) { var rows []io.Reader stat := newStatistics(tw, s) - defer func() { - // recovering if user defined decorator panics for example - if p := recover(); p != nil { - go func() { - _, _ = fmt.Fprintln(b.container, p) - }() - if out := s.debugOut; out != nil { - for _, fn := range []func() (int, error){ - func() (int, error) { - return fmt.Fprintln(out, p) - }, - func() (int, error) { - return out.Write(debug.Stack()) - }, - } { - if _, err := fn(); err != nil { - panic(err) - } - } - } - s.aborted = !s.completed - s.recovered = true - } - frame := &renderFrame{ - rows: rows, - recovered: s.recovered, - } - if !done && (s.completed || s.aborted) { - b.cancel() - frame.shutdown++ - } - b.frameCh <- frame - }() - rows = append(rows, s.draw(stat)) + r, err := s.draw(stat) + if err != nil { + b.frameCh <- &renderFrame{err: err} + return + } + rows = append(rows, r) if s.extender != nil { - rows = s.extender(rows, stat) - } + rows, err = s.extender(rows, stat) + if err != nil { + b.frameCh <- &renderFrame{err: err} + return + } + } + frame := &renderFrame{rows: rows} + if !done && (s.completed || s.aborted) { + frame.shutdown++ + b.cancel() + } + b.frameCh <- frame } select { case b.operateState <- fn: @@ -466,15 +446,15 @@ } } -func (s *bState) draw(stat decor.Statistics) io.Reader { +func (s *bState) draw(stat decor.Statistics) (io.Reader, error) { r, err := s.drawImpl(stat) if err != nil { for _, b := range s.buffers { b.Reset() } - panic(err) - } - return io.MultiReader(r, strings.NewReader("\n")) + return nil, err + } + return io.MultiReader(r, strings.NewReader("\n")), nil } func (s *bState) drawImpl(stat decor.Statistics) (r io.Reader, err error) { diff --git a/bar_option.go b/bar_option.go index d0068c9..953e9d2 100644 --- a/bar_option.go +++ b/bar_option.go @@ -129,11 +129,11 @@ func makeExtenderFunc(filler BarFiller, rev bool) extenderFunc { buf := new(bytes.Buffer) - base := func(rows []io.Reader, stat decor.Statistics) []io.Reader { + base := func(rows []io.Reader, stat decor.Statistics) ([]io.Reader, error) { err := filler.Fill(buf, stat) if err != nil { buf.Reset() - panic(err) + return rows, err } for { b, err := buf.ReadBytes('\n') @@ -143,19 +143,21 @@ rows = append(rows, bytes.NewReader(b)) } buf.Reset() - return rows + return rows, err } if !rev { return base - } else { - return func(rows []io.Reader, stat decor.Statistics) []io.Reader { - rows = base(rows, stat) - for left, right := 0, len(rows)-1; left < right; left, right = left+1, right-1 { - rows[left], rows[right] = rows[right], rows[left] - } - return rows - } + } + return func(rows []io.Reader, stat decor.Statistics) ([]io.Reader, error) { + rows, err := base(rows, stat) + if err != nil { + return rows, err + } + for left, right := 0, len(rows)-1; left < right; left, right = left+1, right-1 { + rows[left], rows[right] = rows[right], rows[left] + } + return rows, err } }