mukan-ignite/ignite/pkg/cliui/clispinner/simple.go
Mukan Erkin Törük c32551b6f7
Some checks failed
Docs Deploy / build_and_deploy (push) Has been cancelled
Generate Docs / cli (push) Has been cancelled
Generate Config Doc / cli (push) Has been cancelled
Go formatting / go-formatting (push) Has been cancelled
Check links / markdown-link-check (push) Has been cancelled
Integration / pre-test (push) Has been cancelled
Integration / test on (push) Has been cancelled
Integration / status (push) Has been cancelled
Lint / Lint Go code (push) Has been cancelled
Test / test (ubuntu-latest) (push) Has been cancelled
refactor: replace all github.com upstream refs with git.cw.tr/mukan-network
2026-05-11 03:36:24 +03:00

162 lines
3.1 KiB
Go

package clispinner
import (
"fmt"
"io"
"os"
"sync"
"time"
"github.com/briandowns/spinner"
"git.cw.tr/mukan-network/mukan-ignite/ignite/pkg/cliui/colors"
)
var (
simpleCharset = spinner.CharSets[4]
simpleRefreshRate = time.Millisecond * 300
simpleColor = colors.Spinner
)
type SimpleSpinner struct {
mu sync.Mutex
writer io.Writer
charset []string
text string
prefix string
color string
active bool
stopChan chan struct{}
}
// newSimpleSpinner creates a new simple spinner.
func newSimpleSpinner(o Options) *SimpleSpinner {
text := o.text
if text == "" {
text = DefaultText
}
charset := o.charset
if len(charset) == 0 {
charset = simpleCharset
}
writer := o.writer
if writer == nil {
writer = os.Stdout
}
return &SimpleSpinner{
charset: charset,
text: text,
writer: writer,
}
}
// SetText sets the text for the spinner.
func (s *SimpleSpinner) SetText(text string) Spinner {
s.mu.Lock()
s.text = text
s.mu.Unlock()
return s
}
// SetPrefix sets the prefix for the spinner.
func (s *SimpleSpinner) SetPrefix(prefix string) Spinner {
s.mu.Lock()
s.prefix = prefix
s.mu.Unlock()
return s
}
// SetCharset sets the charset for the spinner.
func (s *SimpleSpinner) SetCharset(charset []string) Spinner {
s.mu.Lock()
s.charset = charset
s.mu.Unlock()
return s
}
// SetColor sets the color for the spinner (if color functionality is added).
func (s *SimpleSpinner) SetColor(color string) Spinner {
s.mu.Lock()
s.color = color
s.mu.Unlock()
return s
}
// Start begins the spinner animation.
func (s *SimpleSpinner) Start() Spinner {
s.mu.Lock()
if s.active {
s.mu.Unlock()
return s // Do nothing if already active
}
s.active = true
s.stopChan = make(chan struct{})
stop := s.stopChan
writer := s.writer
s.mu.Unlock()
// Start the animation loop in a separate goroutine
go func(stop <-chan struct{}) {
ticker := time.NewTicker(simpleRefreshRate)
defer ticker.Stop()
index := 0
for {
select {
case <-stop: // Stop the spinner
_, _ = fmt.Fprintf(writer, "\r\033[K") // Clear the spinner's line
return
case <-ticker.C: // Update the spinner on each tick
s.mu.Lock()
charset := s.charset
if len(charset) == 0 {
charset = simpleCharset
}
frame := charset[index]
str := fmt.Sprintf("\r%s%s %s", s.prefix, simpleColor(frame), s.text)
_, _ = fmt.Fprint(writer, str) // Update the spinner in the same line
index++
if index >= len(charset) {
index = 0
}
s.mu.Unlock()
}
}
}(stop)
return s
}
// Stop ends the spinner animation.
func (s *SimpleSpinner) Stop() Spinner {
s.mu.Lock()
if !s.active {
s.mu.Unlock()
return s // Do nothing if already inactive
}
stop := s.stopChan
s.active = false
s.stopChan = nil
s.mu.Unlock()
if stop != nil {
close(stop)
}
fmt.Print("\r") // Clear spinner line on stop
return s
}
// IsActive returns whether the spinner is currently active.
func (s *SimpleSpinner) IsActive() bool {
s.mu.Lock()
defer s.mu.Unlock()
return s.active
}
// Writer returns the spinner writer.
func (s *SimpleSpinner) Writer() io.Writer {
return s.writer
}