initial commit

This commit is contained in:
milarin 2023-03-03 19:52:34 +01:00
commit a241803476
6 changed files with 145 additions and 0 deletions

3
go.mod Normal file
View File

@ -0,0 +1,3 @@
module git.milar.in/milarin/statview
go 1.19

0
go.sum Normal file
View File

32
print.go Normal file
View File

@ -0,0 +1,32 @@
package statview
import (
"fmt"
"io"
"strings"
)
func clearEOL(w io.Writer) {
w.Write([]byte{0x1b, 0x5b, 0x4b})
}
func goUp(w io.Writer) {
w.Write([]byte{0x1b, 0x5b, 0x41})
}
func (v *View[K]) print() {
for i := 0; i < v.lastLineAmount; i++ {
goUp(v.writer)
clearEOL(v.writer)
}
lineAmount := 0
for _, task := range v.tasks {
if report, ok := v.lastReports[task]; ok {
lineAmount += len(strings.Split(report.Text, "\n"))
fmt.Fprintln(v.writer, report.Text)
}
}
v.lastLineAmount = lineAmount
}

6
report.go Normal file
View File

@ -0,0 +1,6 @@
package statview
type report[K comparable] struct {
ID K
Text string
}

25
stat_test.go Normal file
View File

@ -0,0 +1,25 @@
package statview
import (
"fmt"
"testing"
"time"
)
func TestStat(t *testing.T) {
view := New[int]()
for i := 0; i < 5; i++ {
view.Add(i)
go func(id int) {
defer view.Done(id)
for p := 0; p <= 100; p++ {
view.Report(id, fmt.Sprintf("task %d: %3d%%", id, p))
time.Sleep(time.Duration(id+1) * 10 * time.Millisecond)
}
}(i)
}
view.Show()
}

79
view.go Normal file
View File

@ -0,0 +1,79 @@
package statview
import (
"io"
"os"
"sort"
"sync"
)
type View[K comparable] struct {
writer io.Writer
sortFunc func(i, j K) bool
lastLineAmount int
lastReports map[K]report[K]
tasks []K
taskMap map[K]struct{}
wg *sync.WaitGroup
reportCh chan report[K]
}
func New[K comparable]() *View[K] {
return NewForWriter[K](os.Stderr)
}
func NewForWriter[K comparable](w io.Writer) *View[K] {
return &View[K]{
writer: w,
tasks: make([]K, 0),
taskMap: map[K]struct{}{},
reportCh: make(chan report[K], 100),
lastReports: map[K]report[K]{},
wg: &sync.WaitGroup{},
}
}
func (v *View[K]) Show() {
go func() {
defer close(v.reportCh)
v.wg.Wait()
}()
for status := range v.reportCh {
v.lastReports[status.ID] = status
v.Add(status.ID)
v.print()
}
}
func (v *View[K]) SortFunc(f func(i, j K) bool) {
v.sortFunc = f
}
func (v *View[K]) Add(task K) {
if _, ok := v.taskMap[task]; ok {
return
}
v.wg.Add(1)
v.tasks = append(v.tasks, task)
v.taskMap[task] = struct{}{}
if v.sortFunc != nil {
sort.Slice(v.tasks, func(i, j int) bool {
return v.sortFunc(v.tasks[i], v.tasks[j])
})
}
}
func (v *View[K]) Report(task K, status string) {
v.reportCh <- report[K]{ID: task, Text: status}
}
func (v *View[K]) Done(task K) {
v.wg.Done()
}