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}