steps.go

  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}