forked from pterm/pterm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmulti_live_printer.go
142 lines (116 loc) · 3.16 KB
/
multi_live_printer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package pterm
import (
"bytes"
"io"
"strings"
"time"
"atomicgo.dev/cursor"
"atomicgo.dev/schedule"
)
var DefaultMultiPrinter = MultiPrinter{
printers: []LivePrinter{},
UpdateDelay: time.Millisecond * 200,
buffers: []*bytes.Buffer{},
area: DefaultArea,
}
type MultiPrinter struct {
IsActive bool
UpdateDelay time.Duration
printers []LivePrinter
buffers []*bytes.Buffer
area AreaPrinter
}
// SetWriter sets the writer for the AreaPrinter.
func (p *MultiPrinter) SetWriter(writer io.Writer) {
cw, ok := writer.(cursor.Writer)
if ok {
p.SetCWriter(cw)
}
}
// SetCWriter sets the writer for the AreaPrinter.
func (p *MultiPrinter) SetCWriter(writer cursor.Writer) {
p.area.SetWriter(writer)
}
// WithWriter returns a fork of the MultiPrinter with a new writer.
func (p MultiPrinter) WithWriter(writer io.Writer) *MultiPrinter {
cw, ok := writer.(cursor.Writer)
if ok {
return p.WithCWriter(cw)
}
return &p
}
// WithCWriter returns a fork of the MultiPrinter with a new writer.
func (p MultiPrinter) WithCWriter(writer cursor.Writer) *MultiPrinter {
p.area.SetWriter(writer)
return &p
}
// WithUpdateDelay returns a fork of the MultiPrinter with a new update delay.
func (p MultiPrinter) WithUpdateDelay(delay time.Duration) *MultiPrinter {
p.UpdateDelay = delay
return &p
}
func (p *MultiPrinter) NewWriter() io.Writer {
buf := bytes.NewBufferString("")
p.buffers = append(p.buffers, buf)
return buf
}
// getString returns all buffers appended and separated by a newline.
func (p *MultiPrinter) getString() string {
var buffer bytes.Buffer
for _, b := range p.buffers {
s := b.String()
s = strings.Trim(s, "\n")
parts := strings.Split(s, "\r") // only get the last override
// check if the last part is empty, if so remove it, repeat until not
// empty. If there is no part left, don't do anything
for len(parts) > 0 && parts[len(parts)-1] == "" {
parts = parts[:len(parts)-1]
}
if len(parts) > 0 {
s = strings.Trim(parts[len(parts)-1], "\n\r")
buffer.WriteString(s)
buffer.WriteString("\n")
}
}
return buffer.String()
}
func (p *MultiPrinter) Start() (*MultiPrinter, error) {
p.IsActive = true
for _, printer := range p.printers {
printer.GenericStart()
}
schedule.Every(p.UpdateDelay, func() bool {
if !p.IsActive {
return false
}
p.area.Update(p.getString())
return true
})
return p, nil
}
func (p *MultiPrinter) Stop() (*MultiPrinter, error) {
p.IsActive = false
for _, printer := range p.printers {
printer.GenericStop()
}
time.Sleep(time.Millisecond * 20)
p.area.Update(p.getString())
p.area.Stop()
return p, nil
}
// GenericStart runs Start, but returns a LivePrinter.
// This is used for the interface LivePrinter.
// You most likely want to use Start instead of this in your program.
func (p MultiPrinter) GenericStart() (*LivePrinter, error) {
p2, _ := p.Start()
lp := LivePrinter(p2)
return &lp, nil
}
// GenericStop runs Stop, but returns a LivePrinter.
// This is used for the interface LivePrinter.
// You most likely want to use Stop instead of this in your program.
func (p MultiPrinter) GenericStop() (*LivePrinter, error) {
p2, _ := p.Stop()
lp := LivePrinter(p2)
return &lp, nil
}