-
Notifications
You must be signed in to change notification settings - Fork 16
/
spinner.go
126 lines (110 loc) · 3.07 KB
/
spinner.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
package main
import (
"fmt"
"time"
"github.com/xyproto/textoutput"
"github.com/xyproto/vt100"
)
var pacmanNoColor = []string{
"| C · · |",
"| C· · |",
"| C · |",
"| C· |",
"| C |",
"| ¤|",
"| · · Ɔ |",
"| · ·Ɔ |",
"| · Ɔ |",
"| ·Ɔ |",
"| Ɔ |",
"|¤· · · |",
}
var pacmanColor = []string{
"<red>| <yellow>C<blue> · ·</blue> <red>|<off>",
"<red>| <blue> <yellow>C<blue>· · <red>|<off>",
"<red>| <blue> <yellow>C<blue> · <red>|<off>",
"<red>| <blue> <yellow>C<blue>· <red>|<off>",
"<red>| <blue> <yellow>C <red>|<off>",
"<red>| <blue> <yellow>¤<red>|<off>",
"<red>| <blue>· · <yellow>Ɔ <red>|<off>",
"<red>| <blue>· ·<yellow>Ɔ<blue> <red>|<off>",
"<red>| <blue>· <yellow>Ɔ <blue> <red>|<off>",
"<red>| <blue>·<yellow>Ɔ<blue> <red>|<off>",
"<red>| <yellow>Ɔ <blue> <red>|<off>",
"<red>|<yellow>¤<blue>· · · <red>|<off>",
}
// Spinner waits a bit, then displays a spinner together with the given message string (msg).
// If the spinner is aborted, the qmsg string is displayed.
// Returns a quit channel (chan bool).
// The spinner is shown asynchronously.
// "true" must be sent to the quit channel once whatever operating that the spinner is spinning for is completed.
func Spinner(c *vt100.Canvas, tty *vt100.TTY, umsg, qmsg string, startIn time.Duration, textColor vt100.AttributeColor) chan bool {
quitChan := make(chan bool)
go func() {
// Divide the startIn time into 5, then wait while listening to the quitChan
// If the quitChan does not receive anything by then, show the spinner
const N = 50
for i := 0; i < N; i++ {
// Check if we should quit or wait
select {
case <-quitChan:
return
default:
// Wait a tiny bit
time.Sleep(startIn / N)
}
}
// If c or tty are nil, use the silent spinner
if (c == nil) || (tty == nil) {
// Wait for a true on the quit channel, then return
<-quitChan
return
}
var (
// Find a good start location
x = uint(int(c.Width()) / 7)
y = uint(int(c.Height()) / 7)
// Get the terminal codes for coloring the given user message
msg = textColor.Get(umsg)
)
// Move the cursor there and write a message
vt100.SetXY(x, y)
fmt.Print(msg)
// Store the position after the message
x += uint(len(msg)) + 1
// Prepare to output colored text
var (
o = textoutput.NewTextOutput(true, true)
counter uint
spinnerAnimation []string
)
// Hide the cursor
vt100.ShowCursor(false)
defer vt100.ShowCursor(true)
// Echo off
vt100.EchoOff()
if envNoColor {
spinnerAnimation = pacmanNoColor
} else {
spinnerAnimation = pacmanColor
}
// Start the spinner
for {
select {
case <-quitChan:
return
default:
vt100.SetXY(x, y)
// Iterate over the 12 different ASCII images as the counter increases
o.Print(spinnerAnimation[counter%12])
counter++
// Wait for a key press (also sleeps just a bit)
switch tty.Key() {
case 27, 113, 17, 3: // esc, q, ctrl-q or ctrl-c
quitMessage(tty, qmsg)
}
}
}
}()
return quitChan
}