From 4806ee7ef95f0f04079856f7753399b7b7aa6330 Mon Sep 17 00:00:00 2001 From: hachem Date: Sat, 29 Aug 2026 11:26:09 +0200 Subject: feat: recommended option filters --- internal/setup/setup.go | 84 +++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 10 deletions(-) (limited to 'internal/setup') diff --git a/internal/setup/setup.go b/internal/setup/setup.go index eafaaa0..c2f8c10 100644 --- a/internal/setup/setup.go +++ b/internal/setup/setup.go @@ -12,10 +12,9 @@ import ( "github.com/charmbracelet/lipgloss" "github.com/hachem-wtf/benson/internal/config" + "github.com/hachem-wtf/benson/internal/fabric" ) -// Run is the server-manager wizard. It configures Minecraft/Fabric versions, -// paths, merge hooks and mods — everything except the Discord bot. func Run() error { cfg := loadConfig() @@ -32,6 +31,8 @@ func Run() error { confirm = true ) + games, loaders, installers := fetchFabricVersions() + form := huh.NewForm( huh.NewGroup( huh.NewNote(). @@ -39,12 +40,16 @@ func Run() error { Description("Configure the server manager.\nThe Discord bot is optional — run `benson setup bot` for that."), ), huh.NewGroup( - huh.NewInput().Title("Minecraft version").Placeholder("1.21.10").Value(&mcVersion).Validate(required("Minecraft version")), - huh.NewInput().Title("Fabric loader version").Placeholder("0.17.3").Value(&fabricLoader).Validate(required("Fabric loader version")), - huh.NewInput().Title("Loader / installer version").Placeholder("1.1.0").Value(&loaderMeta).Validate(required("loader version")), - huh.NewInput().Title("Java path").Description("Leave blank to use 'java' from PATH").Value(&javaPath), - ).Title("Minecraft / Fabric"), + versionField("Minecraft version", "The Minecraft release your server runs — newest stable is recommended", games, &mcVersion, "1.21.10"), + ), + huh.NewGroup( + versionField("Fabric loader version", "The Fabric mod loader that boots your mods — newest is recommended", loaders, &fabricLoader, "0.17.3"), + ), + huh.NewGroup( + versionField("Fabric installer version", "Builds the server jar from the loader — newest is recommended", installers, &loaderMeta, "1.1.0"), + ), huh.NewGroup( + huh.NewInput().Title("Java path").Description("Leave blank to use 'java' from PATH").Value(&javaPath), huh.NewInput().Title("Server location").Description("Live server directory, merged into by 'merge'").Value(&serverLoc), huh.NewInput().Title("Backup location").Description("Where server backups are written").Value(&backupLoc), huh.NewInput().Title("Pre-merge command").Description("Optional shell command run before merging").Value(&preCmd), @@ -81,8 +86,6 @@ func Run() error { return nil } -// RunBot is the Discord-bot wizard. It configures the bot token, channel and -// check interval, leaving the server-manager settings untouched. func RunBot() error { cfg := loadConfig() api := loadAPI() @@ -136,6 +139,68 @@ func RunBot() error { return nil } +func fetchFabricVersions() (games, loaders, installers []string) { + client := fabric.NewClient() + + if gv, err := client.GameVersions(); err == nil { + for _, v := range gv { + if v.Stable { + games = append(games, v.Version) + } + } + } + if lv, err := client.LoaderVersions(); err == nil { + for _, v := range lv { + loaders = append(loaders, v.Version) + } + } + if iv, err := client.InstallerVersions(); err == nil { + for _, v := range iv { + installers = append(installers, v.Version) + } + } + return games, loaders, installers +} + +func versionField(title, desc string, options []string, value *string, placeholder string) huh.Field { + if len(options) == 0 { + return huh.NewInput(). + Title(title). + Placeholder(placeholder). + Value(value). + Validate(required(title)) + } + + *value = defaultOr(*value, options) + return huh.NewSelect[string](). + Title(title). + Description(desc). + Options(recommendedOptions(options)...). + Height(12). + Value(value) +} + +func recommendedOptions(versions []string) []huh.Option[string] { + options := make([]huh.Option[string], len(versions)) + for i, v := range versions { + label := v + if i == 0 { + label = v + " · recommended" + } + options[i] = huh.NewOption(label, v) + } + return options +} + +func defaultOr(current string, options []string) string { + for _, o := range options { + if o == current { + return current + } + } + return options[0] +} + func loadConfig() *config.Config { if cfg, err := config.Load(); err == nil { return cfg @@ -150,7 +215,6 @@ func loadAPI() *config.API { return &config.API{} } -// runForm runs a themed form, reporting whether the user confirmed the write. func runForm(form *huh.Form) (bool, error) { if err := form.WithTheme(emberTheme()).Run(); err != nil { if errors.Is(err, huh.ErrUserAborted) { -- cgit v1.3