// Package configui is the interactive `glint -c` walkthrough: a huh form // that loads the current config, walks the user through every setting, and // writes the result to the config file. package configui import ( "fmt" "glint/internal/config" "github.com/charmbracelet/huh" ) // dailyPresets are friendly daily-note filename formats (label → Go layout), so // users never have to write a raw Go time layout by hand. var dailyPresets = []struct{ label, layout string }{ {"2026-06-28", "2006-01-02"}, {"2026-06-28 Sun", "2006-01-02 Mon"}, {"20260628", "20060102"}, {"2026.06.28", "2006.01.02"}, {"28-06-2026", "02-01-2006"}, } const customLayout = "__custom__" // Run walks the user through the settings and saves them to the config file. func Run() error { cfg, _ := config.Load() // defaults on error theme := orDefault(cfg.Theme, "auto") vaultDir := cfg.VaultDir inboxDir := cfg.InboxDir dailySubdir := orDefault(cfg.DailySubdir, "Daily") glamour := cfg.GlamourStyle spellcheck := orDefault(cfg.Spellcheck, "auto") // Match the current layout to a preset; otherwise offer it as custom. fmtChoice := customLayout for _, p := range dailyPresets { if p.layout == cfg.DailyFormat { fmtChoice = p.layout } } customFmt := cfg.DailyFormat fmtOpts := make([]huh.Option[string], 0, len(dailyPresets)+1) for _, p := range dailyPresets { fmtOpts = append(fmtOpts, huh.NewOption(p.label+" ("+p.layout+")", p.layout)) } fmtOpts = append(fmtOpts, huh.NewOption("Custom…", customLayout)) form := huh.NewForm( huh.NewGroup( huh.NewSelect[string](). Title("Theme"). Description("Colors; auto follows your macOS appearance."). Options( huh.NewOption("auto", "auto"), huh.NewOption("flexoki-light", "flexoki-light"), huh.NewOption("flexoki-dark", "flexoki-dark"), huh.NewOption("charm", "charm"), ).Value(&theme), huh.NewInput(). Title("Vault directory"). Description("Where `glint -v` opens, from anywhere. Blank = none."). Placeholder("/Users/you/Notes"). Value(&vaultDir), huh.NewInput(). Title("Inbox directory"). Description("Where `glint -n -i` and save-as land. Blank = the directory you run glint in."). Value(&inboxDir), huh.NewInput(). Title("Daily notes subfolder"). Description("Daily notes live in //."). Value(&dailySubdir), huh.NewSelect[string](). Title("Daily filename format"). Options(fmtOpts...). Value(&fmtChoice), huh.NewSelect[string](). Title("Preview style"). Description("Glamour style for the read preview. Blank follows the theme."). Options( huh.NewOption("follow theme", ""), huh.NewOption("dark", "dark"), huh.NewOption("light", "light"), huh.NewOption("dracula", "dracula"), huh.NewOption("tokyo-night", "tokyo-night"), ).Value(&glamour), huh.NewSelect[string](). Title("Spellcheck"). Description("Red undercurl on misspelled prose. auto = on for notes, off for code files."). Options( huh.NewOption("auto", "auto"), huh.NewOption("on", "on"), huh.NewOption("off", "off"), ).Value(&spellcheck), ), huh.NewGroup( huh.NewInput(). Title("Custom daily format (Go layout)"). Description("Reference date is Mon Jan 2 2006 — e.g. 2006-01-02 or 20060102."). Value(&customFmt), ).WithHideFunc(func() bool { return fmtChoice != customLayout }), ) if err := form.Run(); err != nil { return err } dailyFmt := fmtChoice if fmtChoice == customLayout { dailyFmt = customFmt } out := config.Config{ Theme: theme, VaultDir: vaultDir, InboxDir: inboxDir, DailySubdir: dailySubdir, DailyFormat: dailyFmt, GlamourStyle: glamour, Spellcheck: spellcheck, // Export fonts aren't part of the wizard; preserve any existing values // so a `glint -c` run doesn't silently drop them. FontDisplay: cfg.FontDisplay, FontBody: cfg.FontBody, FontMono: cfg.FontMono, } path := config.Path() if err := config.Save(out, path); err != nil { return err } fmt.Println("Saved", path) return nil } func orDefault(v, def string) string { if v == "" { return def } return v }