diff --git a/bar.go b/bar.go index b6d51ad..9b0ca2c 100644 --- a/bar.go +++ b/bar.go @@ -451,52 +451,76 @@ } func (s *bState) draw(stat decor.Statistics) io.Reader { - return io.MultiReader(s.drawImpl(stat), strings.NewReader("\n")) -} - -func (s *bState) drawImpl(stat decor.Statistics) io.Reader { - decorFiller := func(buf *bytes.Buffer, decorators []decor.Decorator) (int, bool) { - tw := stat.AvailableWidth + r, err := s.drawImpl(stat) + if err != nil { + s.buffers[0].Reset() + s.buffers[1].Reset() + s.buffers[2].Reset() + panic(err) + } + return io.MultiReader(r, strings.NewReader("\n")) +} + +func (s *bState) drawImpl(stat decor.Statistics) (r io.Reader, err error) { + type decorResult struct { + width int + truncate bool + } + decorFiller := func(buf *bytes.Buffer, decorators []decor.Decorator) (res decorResult, err error) { + res.width = stat.AvailableWidth for _, d := range decorators { str := d.Decor(stat) - if stat.AvailableWidth > 0 { + if stat.AvailableWidth > 0 && err == nil { stat.AvailableWidth -= runewidth.StringWidth(stripansi.Strip(str)) - mustWriteString(buf, str) - } - } - return tw, stat.AvailableWidth < 0 - } - + _, err = buf.WriteString(str) + } + } + res.truncate = stat.AvailableWidth < 0 + return res, err + } bufP, bufB, bufA := s.buffers[0], s.buffers[1], s.buffers[2] - twP, truncateP := decorFiller(bufP, s.pDecorators) + resP, err := decorFiller(bufP, s.pDecorators) + if err != nil { + return nil, err + } if !s.trimSpace && stat.AvailableWidth >= 2 { - mustWriteString(bufB, " ") - defer mustWriteString(bufB, " ") + err = bufB.WriteByte(' ') + if err != nil { + return nil, err + } + defer func() { + if err == nil { + err = bufB.WriteByte(' ') + } + }() stat.AvailableWidth -= 2 } - twA, truncateA := decorFiller(bufA, s.aDecorators) - - if truncateP { - trunc := strings.NewReader(runewidth.Truncate(stripansi.Strip(bufP.String()), twP, "…")) + resA, err := decorFiller(bufA, s.aDecorators) + if err != nil { + return nil, err + } + + if resP.truncate { + trunc := strings.NewReader(runewidth.Truncate(stripansi.Strip(bufP.String()), resP.width, "…")) bufP.Reset() - return trunc - } - - if truncateA { - trunc := strings.NewReader(runewidth.Truncate(stripansi.Strip(bufA.String()), twA, "…")) + return trunc, nil + } + + if resA.truncate { + trunc := strings.NewReader(runewidth.Truncate(stripansi.Strip(bufA.String()), resA.width, "…")) bufA.Reset() - return io.MultiReader(bufP, bufB, trunc) - } - - err := s.filler.Fill(bufB, stat) + return io.MultiReader(bufP, bufB, trunc), nil + } + + err = s.filler.Fill(bufB, stat) if err != nil { - panic(err) - } - - return io.MultiReader(bufP, bufB, bufA) + return nil, err + } + + return io.MultiReader(bufP, bufB, bufA), nil } func (s *bState) wSyncTable() [][]chan int { @@ -611,10 +635,3 @@ } return d } - -func mustWriteString(sw io.StringWriter, str string) { - _, err := sw.WriteString(str) - if err != nil { - panic(err) - } -}