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.
16//
17//nolint:ireturn // generic return by design
18func Spin[T any](title string, fn func() (T, error)) (T, error) {
19	if IsPlain() {
20		return fn()
21	}
22
23	var result T
24
25	var fnErr error
26
27	spinErr := spinner.New().
28		Title(title).
29		Action(func() {
30			result, fnErr = fn()
31		}).
32		Run()
33	if spinErr != nil {
34		return result, fmt.Errorf("spinner: %w", spinErr)
35	}
36
37	return result, fnErr
38}
39
40// SpinVoid executes fn while displaying a spinner with the given title.
41// Use for functions that only return an error.
42// In non-interactive mode, the function runs directly without spinner UI.
43func SpinVoid(title string, fn func() error) error {
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}