-
Notifications
You must be signed in to change notification settings - Fork 44
/
Copy pathspinner.go
138 lines (120 loc) · 2.6 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
127
128
129
130
131
132
133
134
135
136
137
138
//Inspaired by https://github.com/oclif/cli-ux
package ux
import (
"fmt"
"io"
"os"
"runtime"
"time"
"github.com/ucloud/ucloud-cli/ansi"
)
const windows = "windows"
// Spinner type
type Spinner struct {
out io.Writer
frames []rune
framesPerSecond int
DoingText string
DoneText string
TimeoutText string
ticker *time.Ticker
output string
}
// Start start render
func (s *Spinner) Start(doingText string) {
if doingText != "" {
s.DoingText = doingText
}
s.ticker = time.NewTicker(time.Second / time.Duration(s.framesPerSecond))
s.render()
}
// Stop stop render
func (s *Spinner) Stop() {
s.ticker.Stop()
s.reset()
output := fmt.Sprintf("%s...%s\n", s.DoingText, s.DoneText)
fmt.Fprintf(s.out, output)
}
// Timeout stop render
func (s *Spinner) Timeout() {
s.ticker.Stop()
s.reset()
output := fmt.Sprintf("%s...%s\n", s.DoingText, s.TimeoutText)
fmt.Fprintf(s.out, output)
}
// Fail stop render
func (s *Spinner) Fail(err error) {
s.ticker.Stop()
s.reset()
output := fmt.Sprintf("%s...fail: %v\n", s.DoingText, err)
fmt.Fprintf(s.out, output)
}
func (s *Spinner) reset() {
if s.output == "" {
return
}
fmt.Printf(ansi.CursorLeft + ansi.CursorUp(1) + ansi.EraseDown)
s.output = ""
}
func (s *Spinner) render() {
nextFrame := s.newFrameFactory()
go func() {
send := false
for range s.ticker.C {
if runtime.GOOS == windows {
if !send {
fmt.Printf("%s...\n", s.DoingText)
send = true
}
continue
}
frame := nextFrame()
s.reset()
s.output = fmt.Sprintf("%s...%c\n", s.DoingText, frame)
fmt.Printf(s.output)
}
}()
}
func (s *Spinner) newFrameFactory() func() rune {
index := 0
size := len(s.frames)
return func() rune {
char := s.frames[index%size]
index++
return char
}
}
var spinnerFrames = []rune{'⣾', '⣽', '⣻', '⢿', '⡿', '⣟', '⣯', '⣷'}
// DotSpinner dot spinner
var DotSpinner = NewDotSpinner(os.Stdout)
// NewDotSpinner get new DotSpinner instance
func NewDotSpinner(out io.Writer) *Spinner {
return &Spinner{
out: out,
frames: spinnerFrames,
framesPerSecond: 12,
DoingText: "running",
DoneText: "done",
TimeoutText: "timeout",
}
}
// Refresh 刷新显示文本
type Refresh struct {
out io.Writer
reset bool
}
// Do 刷新显示
func (r *Refresh) Do(text string) {
if r.reset {
fmt.Fprintf(r.out, ansi.CursorLeft+ansi.CursorUp(1)+ansi.EraseDown)
} else {
r.reset = true
}
fmt.Fprintln(r.out, text)
}
// NewRefresh create a new Refresh instance
func NewRefresh() *Refresh {
return &Refresh{
out: os.Stdout,
}
}