-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathhud.go
More file actions
155 lines (134 loc) · 2.74 KB
/
hud.go
File metadata and controls
155 lines (134 loc) · 2.74 KB
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
143
144
145
146
147
148
149
150
151
152
153
154
155
package console
import (
"bytes"
"io"
"os"
"sync"
"sync/atomic"
"time"
)
var hud Hud
type Hud struct {
active atomic.Bool
in_render atomic.Bool
guard sync.Mutex
renderer_func RendererFunc
num_lines int
lines bytes.Buffer
newline_printed bool
start_time time.Time
final_message []Cell
}
type Component interface {
Render(line []Cell) (n int, err error)
}
type RendererFunc func(h *Hud)
// Set a function to render your Hud
func RenderFunc(f RendererFunc) {
hud.guard.Lock()
hud.renderer_func = f
hud.guard.Unlock()
}
// non-goroutine-safe
// re-render the hud
func (h *Hud) render() {
h.in_render.Store(true)
h.num_lines = 0
h.lines.Reset()
h.renderer_func(h)
h.in_render.Store(false)
}
func (h *Hud) Exiting() bool {
return !h.active.Load()
}
// non-goroutine-safe
func (h *Hud) erase(w io.Writer, lines int) {
if lines == 0 {
return
}
var err error
// erase the line
if _, err = w.Write(ansics_erase_line); err != nil {
panic(err)
}
for i := 0; i < lines-1; i++ {
// move the cursor up 1
if _, err = w.Write(ansics_cursor_up); err != nil {
panic(err)
}
// erase the line
if _, err = w.Write(ansics_erase_line); err != nil {
panic(err)
}
}
// move cursor to 0 cell
if _, err = w.Write(ansi_cr); err != nil {
panic(err)
}
}
// render a line
func (h *Hud) Line(components ...Component) {
if !h.in_render.Load() {
panic("not in render")
}
// lines need to have a newline printed before them, not after.
// we don't want to have an ugly space below the bottom of the Hud
if !h.newline_printed {
h.lines.WriteByte('\n')
h.newline_printed = true
}
line_width := Width()
if line_width == 0 {
return
}
line := make([]Cell, line_width)
index := 0
for _, component := range components {
n, err := component.Render(line[index:])
if err != nil {
WriteText(line, err.Error(), 0, 0)
break
}
index += n
if index >= line_width {
break
}
}
render_line(&h.lines, line)
h.num_lines++
}
func (h *Hud) present(w io.Writer) {
w.Write(h.lines.Bytes())
}
func (h *Hud) swap() {
// save the old number of lines
num_lines := hud.num_lines
// render the new Hud
hud.render()
// erase and present in one buffer to avoid flickering
var swap_buffer bytes.Buffer
// erase the old Hud
hud.erase(&swap_buffer, num_lines)
// print the new Hud
hud.present(&swap_buffer)
os.Stdout.Write(swap_buffer.Bytes())
}
// Erases the previously printed hud and renders the updated version
func SwapHud() {
hud.guard.Lock()
hud.swap()
hud.guard.Unlock()
}
// Automatically swap at the designated interval
func SwapInterval(t time.Duration) {
go func() {
for {
if hud.active.Load() {
SwapHud()
} else {
return
}
time.Sleep(t)
}
}()
}