...
1
16
17
21
22
23 package fidget
24
25 import (
26 "fmt"
27 "io"
28 "runtime"
29 "sync"
30 "time"
31 )
32
33
34
35 var unicodeSpinnerFrames = []string{
36 "◐",
37 "◓",
38 "◑",
39 "◒",
40 }
41
42
43
44 var asciiSpinnerFrames = []string{
45 "<",
46 "^",
47 ">",
48 "v",
49 }
50
51
52
53
54 type Spinner struct {
55 frames []string
56 stop chan struct{}
57 ticker *time.Ticker
58 writer io.Writer
59 mu *sync.Mutex
60
61 prefix string
62 suffix string
63 start time.Time
64 }
65
66
67 func NewSpinner(w io.Writer) *Spinner {
68
69 frames := unicodeSpinnerFrames
70 if runtime.GOOS == "windows" {
71 frames = asciiSpinnerFrames
72 }
73
74 return &Spinner{
75 frames: frames,
76 stop: make(chan struct{}, 1),
77 ticker: time.NewTicker(time.Millisecond * 200),
78 mu: &sync.Mutex{},
79 writer: w,
80 start: time.Now(),
81 }
82 }
83
84
85 func (s *Spinner) SetPrefix(prefix string) {
86 s.mu.Lock()
87 s.prefix = prefix
88 s.mu.Unlock()
89 }
90
91
92 func (s *Spinner) SetSuffix(suffix string) {
93 s.mu.Lock()
94
95
96 if len(suffix) < len(s.suffix) {
97 spacingLength := len(s.prefix) + len(s.suffix)
98 fmt.Fprintf(s.writer, "\r%*s", spacingLength, "")
99 }
100 s.suffix = suffix
101
102
103 fmt.Print("\r")
104 s.mu.Unlock()
105 }
106
107
108 func (s *Spinner) Start() {
109 go func() {
110 for {
111 for _, frame := range s.frames {
112 select {
113 case <-s.stop:
114 return
115 case <-s.ticker.C:
116 func() {
117 s.mu.Lock()
118 defer s.mu.Unlock()
119 fmt.Fprintf(s.writer, "\r%s%s%s", s.prefix, frame, s.suffix)
120 }()
121 }
122 }
123 }
124 }()
125 }
126
127
128 func (s *Spinner) Stop() {
129 s.stop <- struct{}{}
130 }
131
132
133 func (s *Spinner) TimeSpent() string {
134 currentTime := time.Now()
135 timeElapsed := currentTime.Sub(s.start)
136
137
138
139
140 if timeElapsed > time.Minute {
141 return fmt.Sprintf("%.0fm", timeElapsed.Minutes())
142 } else if timeElapsed < time.Minute && timeElapsed > time.Second {
143 return fmt.Sprintf("%.0fs", timeElapsed.Seconds())
144 } else if timeElapsed < time.Second && timeElapsed > time.Millisecond {
145 return fmt.Sprintf("%dms", timeElapsed.Nanoseconds()/int64(time.Millisecond))
146 }
147
148
149 return ""
150 }
151
View as plain text