src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

statusbar.go (1288B)


      1 package statusbar
      2 
      3 import (
      4 	"context"
      5 	"fmt"
      6 	"strings"
      7 	"sync"
      8 	"time"
      9 
     10 	"code.dwrz.net/src/pkg/log"
     11 )
     12 
     13 type Block interface {
     14 	Name() string
     15 	Render(ctx context.Context) (string, error)
     16 }
     17 
     18 type Parameters struct {
     19 	Blocks    []Block
     20 	Log       *log.Logger
     21 	Separator string
     22 }
     23 
     24 type StatusBar struct {
     25 	b      *strings.Builder
     26 	blocks []Block
     27 	l      *log.Logger
     28 	sep    string
     29 }
     30 
     31 func (s *StatusBar) Render(ctx context.Context) string {
     32 	defer s.b.Reset()
     33 
     34 	fmt.Fprintf(s.b, "%s ", s.sep)
     35 
     36 	var (
     37 		timeout, cancel = context.WithTimeout(ctx, 100*time.Millisecond)
     38 		outputs         = make([]string, len(s.blocks))
     39 		wg              sync.WaitGroup
     40 	)
     41 	defer cancel()
     42 
     43 	wg.Add(len(s.blocks))
     44 
     45 	for i, b := range s.blocks {
     46 		go func(i int, b Block) {
     47 			defer wg.Done()
     48 
     49 			text, err := b.Render(timeout)
     50 			if err != nil {
     51 				s.l.Error.Printf(
     52 					"failed to render %s: %v",
     53 					b.Name(), err,
     54 				)
     55 				outputs[i] = ""
     56 			} else {
     57 				outputs[i] = text
     58 			}
     59 		}(i, b)
     60 	}
     61 
     62 	wg.Wait()
     63 
     64 	for i, o := range outputs {
     65 		s.b.WriteString(o)
     66 
     67 		if i < len(outputs)-1 {
     68 			fmt.Fprintf(s.b, " %s ", s.sep)
     69 		}
     70 	}
     71 
     72 	return s.b.String()
     73 }
     74 
     75 func New(p Parameters) *StatusBar {
     76 	return &StatusBar{
     77 		b:      &strings.Builder{},
     78 		blocks: p.Blocks,
     79 		l:      p.Log,
     80 		sep:    p.Separator,
     81 	}
     82 }