mirror of
https://github.com/ollama/ollama.git
synced 2026-07-07 00:08:13 +00:00
108 lines
1.8 KiB
Go
108 lines
1.8 KiB
Go
package progress
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
"sync"
|
|
"sync/atomic"
|
|
"time"
|
|
)
|
|
|
|
type Spinner struct {
|
|
mu sync.Mutex
|
|
message atomic.Value
|
|
messageWidth int
|
|
|
|
parts []string
|
|
|
|
value int
|
|
|
|
done chan struct{}
|
|
stopOnce sync.Once
|
|
started time.Time
|
|
stopped time.Time
|
|
}
|
|
|
|
func NewSpinner(message string) *Spinner {
|
|
s := &Spinner{
|
|
parts: []string{
|
|
"⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏",
|
|
},
|
|
started: time.Now(),
|
|
done: make(chan struct{}),
|
|
}
|
|
s.SetMessage(message)
|
|
go s.start()
|
|
return s
|
|
}
|
|
|
|
func (s *Spinner) SetMessage(message string) {
|
|
s.message.Store(message)
|
|
}
|
|
|
|
func (s *Spinner) String() string {
|
|
var sb strings.Builder
|
|
|
|
if message, ok := s.message.Load().(string); ok && len(message) > 0 {
|
|
message := strings.TrimSpace(message)
|
|
if s.messageWidth > 0 && len(message) > s.messageWidth {
|
|
message = message[:s.messageWidth]
|
|
}
|
|
|
|
fmt.Fprintf(&sb, "%s", message)
|
|
if padding := s.messageWidth - sb.Len(); padding > 0 {
|
|
sb.WriteString(strings.Repeat(" ", padding))
|
|
}
|
|
|
|
sb.WriteString(" ")
|
|
}
|
|
|
|
s.mu.Lock()
|
|
value := s.value
|
|
stopped := !s.stopped.IsZero()
|
|
s.mu.Unlock()
|
|
if !stopped {
|
|
spinner := s.parts[value]
|
|
sb.WriteString(spinner)
|
|
sb.WriteString(" ")
|
|
}
|
|
|
|
return sb.String()
|
|
}
|
|
|
|
func (s *Spinner) start() {
|
|
ticker := time.NewTicker(100 * time.Millisecond)
|
|
defer ticker.Stop()
|
|
|
|
s.mu.Lock()
|
|
if !s.stopped.IsZero() {
|
|
s.mu.Unlock()
|
|
return
|
|
}
|
|
s.mu.Unlock()
|
|
for {
|
|
select {
|
|
case <-s.done:
|
|
return
|
|
case <-ticker.C:
|
|
s.mu.Lock()
|
|
if !s.stopped.IsZero() {
|
|
s.mu.Unlock()
|
|
return
|
|
}
|
|
s.value = (s.value + 1) % len(s.parts)
|
|
s.mu.Unlock()
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *Spinner) Stop() {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
if s.stopped.IsZero() {
|
|
s.stopped = time.Now()
|
|
}
|
|
s.stopOnce.Do(func() {
|
|
close(s.done)
|
|
})
|
|
}
|