package statusline import ( "fmt" "sync" "time" ) type stopWatch struct { inner StatusLine precision time.Duration start time.Time line string once sync.Once lines chan string end1 chan bool end2 chan struct{} } func StopWatch(sl StatusLine, precision time.Duration) StatusLine { return &stopWatch{ inner: sl, precision: precision, lines: make(chan string), end1: make(chan bool), end2: make(chan struct{}), } } func (sw *stopWatch) startWorker() { go func() { sw.start = time.Now() ticker := time.NewTicker(sw.precision) for { select { case <-ticker.C: sw.tick() case sw.line = <-sw.lines: sw.tick() case keep := <-sw.end1: sw.tick() sw.inner.End(keep) ticker.Stop() sw.end2 <- struct{}{} close(sw.end2) return } } }() } func (sw *stopWatch) tick() { d := time.Now().Sub(sw.start).Round(sw.precision) sw.inner.Put(fmt.Sprintf("[ %v ] %s", d, sw.line)) } func (sl *stopWatch) Put(line string) { sl.once.Do(sl.startWorker) sl.lines <- line } func (sl *stopWatch) End(keep bool) { sl.once.Do(sl.startWorker) sl.end1 <- keep close(sl.lines) close(sl.end1) <-sl.end2 }