1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5package init
6
7import (
8 "errors"
9 "fmt"
10
11 "github.com/charmbracelet/huh"
12 "github.com/spf13/cobra"
13
14 "git.secluded.site/lune/internal/config"
15 "git.secluded.site/lune/internal/ui"
16)
17
18// runUIPrefsStep runs the UI preferences configuration step.
19func runUIPrefsStep(cfg *config.Config) wizardNav {
20 color := cfg.UI.Color
21 if color == "" {
22 color = colorAuto
23 }
24
25 err := huh.NewSelect[string]().
26 Title("Color output").
27 Description("When should lune use colored output?").
28 Options(
29 huh.NewOption("Auto (detect terminal capability)", colorAuto),
30 huh.NewOption("Always", "always"),
31 huh.NewOption("Never", "never"),
32 ).
33 Value(&color).
34 Run()
35 if err != nil {
36 if errors.Is(err, huh.ErrUserAborted) {
37 return navQuit
38 }
39
40 return navQuit
41 }
42
43 cfg.UI.Color = color
44
45 return navNext
46}
47
48// runAreasStep runs the areas configuration step.
49func runAreasStep(cfg *config.Config) wizardNav {
50 return manageAreasAsStep(cfg)
51}
52
53// runNotebooksStep runs the notebooks configuration step.
54func runNotebooksStep(cfg *config.Config) wizardNav {
55 return manageNotebooksAsStep(cfg)
56}
57
58// runHabitsStep runs the habits configuration step.
59func runHabitsStep(cfg *config.Config) wizardNav {
60 return manageHabitsAsStep(cfg)
61}
62
63// runDefaultsStep runs the defaults configuration step.
64func runDefaultsStep(cfg *config.Config) wizardNav {
65 hasAreas := len(cfg.Areas) > 0
66 hasNotebooks := len(cfg.Notebooks) > 0
67
68 if !hasAreas && !hasNotebooks {
69 return navNext
70 }
71
72 if hasAreas {
73 nav := selectDefaultAreaWithNav(cfg)
74 if nav != navNext {
75 return nav
76 }
77 }
78
79 if hasNotebooks {
80 return selectDefaultNotebookWithNav(cfg)
81 }
82
83 return navNext
84}
85
86// runAccessTokenStep runs the access token configuration step.
87func runAccessTokenStep(cmd *cobra.Command) wizardNav {
88 err := configureAccessToken(cmd)
89 if errors.Is(err, errQuit) {
90 return navQuit
91 }
92
93 if err != nil {
94 out := cmd.OutOrStdout()
95 fmt.Fprintln(out, ui.Error.Render("Token configuration failed: "+err.Error()))
96
97 var skip bool
98
99 skipErr := huh.NewConfirm().
100 Title("Skip token configuration?").
101 Description("You can configure it later with 'lune init'.").
102 Affirmative("Skip for now").
103 Negative("Go back").
104 Value(&skip).
105 Run()
106 if skipErr != nil {
107 return navQuit
108 }
109
110 if skip {
111 return navNext
112 }
113
114 return navBack
115 }
116
117 return navNext
118}
119
120// selectDefaultAreaWithNav selects the default area and returns navigation.
121func selectDefaultAreaWithNav(cfg *config.Config) wizardNav {
122 options := []huh.Option[string]{huh.NewOption("None", "")}
123 for _, area := range cfg.Areas {
124 options = append(options, huh.NewOption(area.Name+" ("+area.Key+")", area.Key))
125 }
126
127 choice, nav := runDefaultSelect("Default area", "Used when no area is specified.", cfg.Defaults.Area, options)
128 if nav != navNext || choice == "" {
129 return nav
130 }
131
132 cfg.Defaults.Area = choice
133
134 return navNext
135}
136
137// selectDefaultNotebookWithNav selects the default notebook and returns navigation.
138func selectDefaultNotebookWithNav(cfg *config.Config) wizardNav {
139 options := []huh.Option[string]{huh.NewOption("None", "")}
140 for _, nb := range cfg.Notebooks {
141 options = append(options, huh.NewOption(nb.Name+" ("+nb.Key+")", nb.Key))
142 }
143
144 desc := "Used when no notebook is specified."
145 choice, nav := runDefaultSelect("Default notebook", desc, cfg.Defaults.Notebook, options)
146
147 if nav != navNext || choice == "" {
148 return nav
149 }
150
151 cfg.Defaults.Notebook = choice
152
153 return navNext
154}
155
156func runDefaultSelect(title, desc, current string, options []huh.Option[string]) (string, wizardNav) {
157 options = append(options,
158 huh.NewOption("← Back", choiceBack),
159 huh.NewOption("Next →", choiceNext),
160 )
161
162 value := current
163
164 err := huh.NewSelect[string]().
165 Title(title).
166 Description(desc).
167 Options(options...).
168 Value(&value).
169 Run()
170 if err != nil {
171 return "", navQuit
172 }
173
174 switch value {
175 case choiceBack:
176 return "", navBack
177 case choiceNext:
178 return "", navNext
179 default:
180 return value, navNext
181 }
182}