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}