initial commit
This commit is contained in:
commit
a241803476
32
print.go
Normal file
32
print.go
Normal 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
6
report.go
Normal file
@ -0,0 +1,6 @@
|
||||
package statview
|
||||
|
||||
type report[K comparable] struct {
|
||||
ID K
|
||||
Text string
|
||||
}
|
25
stat_test.go
Normal file
25
stat_test.go
Normal 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
79
view.go
Normal 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()
|
||||
}
|
Loading…
Reference in New Issue
Block a user