spinner.go

 1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
 2//
 3// SPDX-License-Identifier: AGPL-3.0-or-later
 4
 5package ui
 6
 7import (
 8	"fmt"
 9
10	"github.com/charmbracelet/huh/spinner"
11)
12
13// Spin executes fn while displaying a spinner with the given title.
14// Uses generics to preserve the return type of the wrapped function.
15// In non-interactive mode, the function runs directly without spinner UI.
16func Spin[T any](title string, fn func() (T, error)) (T, error) {
17	// In plain/non-interactive mode, just run the function directly
18	if IsPlain() {
19		return fn()
20	}
21
22	var result T
23
24	var fnErr error
25
26	spinErr := spinner.New().
27		Title(title).
28		Action(func() {
29			result, fnErr = fn()
30		}).
31		Run()
32	if spinErr != nil {
33		return result, fmt.Errorf("spinner: %w", spinErr)
34	}
35
36	return result, fnErr
37}
38
39// SpinVoid executes fn while displaying a spinner with the given title.
40// Use for functions that only return an error.
41// In non-interactive mode, the function runs directly without spinner UI.
42func SpinVoid(title string, fn func() error) error {
43	// In plain/non-interactive mode, just run the function directly
44	if IsPlain() {
45		return fn()
46	}
47
48	var fnErr error
49
50	spinErr := spinner.New().
51		Title(title).
52		Action(func() {
53			fnErr = fn()
54		}).
55		Run()
56	if spinErr != nil {
57		return fmt.Errorf("spinner: %w", spinErr)
58	}
59
60	return fnErr
61}