From f5ef0f6c6e0fcf8de66896658b8ce56f42cd3742 Mon Sep 17 00:00:00 2001 From: Amolith Date: Tue, 23 Dec 2025 14:23:32 -0700 Subject: [PATCH] feat(habit): add list subcommand Assisted-by: Claude Opus 4.5 via Crush --- cmd/habit/habit.go | 1 + cmd/habit/list.go | 85 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 cmd/habit/list.go diff --git a/cmd/habit/habit.go b/cmd/habit/habit.go index c7fd4595240351ba1aaa9d6325007d83470a4fec..9ec27d818bb099bd14e265e1783527e9929dd23a 100644 --- a/cmd/habit/habit.go +++ b/cmd/habit/habit.go @@ -15,5 +15,6 @@ var Cmd = &cobra.Command{ } func init() { + Cmd.AddCommand(ListCmd) Cmd.AddCommand(TrackCmd) } diff --git a/cmd/habit/list.go b/cmd/habit/list.go new file mode 100644 index 0000000000000000000000000000000000000000..69fddf49f98460990b1c5feb581e5eb181c92210 --- /dev/null +++ b/cmd/habit/list.go @@ -0,0 +1,85 @@ +// SPDX-FileCopyrightText: Amolith +// +// SPDX-License-Identifier: AGPL-3.0-or-later + +package habit + +import ( + "encoding/json" + "fmt" + + "git.secluded.site/lune/internal/config" + "git.secluded.site/lune/internal/ui" + "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/table" + "github.com/spf13/cobra" +) + +// ListCmd lists configured habits. +var ListCmd = &cobra.Command{ + Use: "list", + Short: "List configured habits", + Long: `List habits configured in lune. + +Habits are copied from the Lunatask desktop app during 'lune init'.`, + RunE: runList, +} + +func init() { + ListCmd.Flags().Bool("json", false, "Output as JSON") +} + +func runList(cmd *cobra.Command, _ []string) error { + cfg, err := config.Load() + if err != nil { + return err + } + + if len(cfg.Habits) == 0 { + fmt.Fprintln(cmd.OutOrStdout(), "No habits configured") + + return nil + } + + jsonFlag, _ := cmd.Flags().GetBool("json") + if jsonFlag { + return outputJSON(cmd, cfg.Habits) + } + + return outputTable(cmd, cfg.Habits) +} + +func outputJSON(cmd *cobra.Command, habits []config.Habit) error { + enc := json.NewEncoder(cmd.OutOrStdout()) + enc.SetIndent("", " ") + + if err := enc.Encode(habits); err != nil { + return fmt.Errorf("encoding JSON: %w", err) + } + + return nil +} + +func outputTable(cmd *cobra.Command, habits []config.Habit) error { + rows := make([][]string, 0, len(habits)) + + for _, habit := range habits { + rows = append(rows, []string{habit.Key, habit.Name}) + } + + tbl := table.New(). + Headers("KEY", "NAME"). + Rows(rows...). + StyleFunc(func(row, col int) lipgloss.Style { + if row == table.HeaderRow { + return ui.TableHeaderStyle() + } + + return lipgloss.NewStyle() + }). + Border(ui.TableBorder()) + + fmt.Fprintln(cmd.OutOrStdout(), tbl.Render()) + + return nil +}