list.go

  1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
  2//
  3// SPDX-License-Identifier: AGPL-3.0-or-later
  4
  5package area
  6
  7import (
  8	"encoding/json"
  9	"fmt"
 10
 11	"git.secluded.site/lune/internal/config"
 12	"git.secluded.site/lune/internal/ui"
 13	"github.com/charmbracelet/lipgloss"
 14	"github.com/charmbracelet/lipgloss/table"
 15	"github.com/spf13/cobra"
 16)
 17
 18// ListCmd lists configured areas and their goals.
 19var ListCmd = &cobra.Command{
 20	Use:   "list",
 21	Short: "List configured areas",
 22	Long: `List areas configured in lune.
 23
 24Areas are copied from the Lunatask desktop app during 'lune init'.
 25Each area may have goals associated with it.`,
 26	RunE: runList,
 27}
 28
 29func init() {
 30	ListCmd.Flags().Bool("json", false, "Output as JSON")
 31}
 32
 33func runList(cmd *cobra.Command, _ []string) error {
 34	cfg, err := config.Load()
 35	if err != nil {
 36		fmt.Fprintln(cmd.ErrOrStderr(), ui.Error.Render("Config not found; run 'lune init' to configure areas"))
 37
 38		return err
 39	}
 40
 41	if len(cfg.Areas) == 0 {
 42		fmt.Fprintln(cmd.OutOrStdout(), "No areas configured")
 43
 44		return nil
 45	}
 46
 47	jsonFlag, _ := cmd.Flags().GetBool("json")
 48	if jsonFlag {
 49		return outputJSON(cmd, cfg.Areas)
 50	}
 51
 52	return outputTable(cmd, cfg.Areas)
 53}
 54
 55func outputJSON(cmd *cobra.Command, areas []config.Area) error {
 56	enc := json.NewEncoder(cmd.OutOrStdout())
 57	enc.SetIndent("", "  ")
 58
 59	if err := enc.Encode(areas); err != nil {
 60		return fmt.Errorf("encoding JSON: %w", err)
 61	}
 62
 63	return nil
 64}
 65
 66func outputTable(cmd *cobra.Command, areas []config.Area) error {
 67	rows := make([][]string, 0, len(areas))
 68
 69	for _, area := range areas {
 70		goals := formatGoals(area.Goals)
 71		rows = append(rows, []string{area.Key, area.Name, goals})
 72	}
 73
 74	tbl := table.New().
 75		Headers("KEY", "NAME", "GOALS").
 76		Rows(rows...).
 77		StyleFunc(func(row, col int) lipgloss.Style {
 78			if row == table.HeaderRow {
 79				return ui.Bold
 80			}
 81
 82			return lipgloss.NewStyle()
 83		}).
 84		Border(lipgloss.HiddenBorder())
 85
 86	fmt.Fprintln(cmd.OutOrStdout(), tbl.Render())
 87
 88	return nil
 89}
 90
 91func formatGoals(goals []config.Goal) string {
 92	if len(goals) == 0 {
 93		return "-"
 94	}
 95
 96	keys := make([]string, len(goals))
 97	for i, g := range goals {
 98		keys[i] = g.Key
 99	}
100
101	if len(keys) <= 3 {
102		return joinKeys(keys)
103	}
104
105	return joinKeys(keys[:3]) + fmt.Sprintf(" (+%d)", len(keys)-3)
106}
107
108func joinKeys(keys []string) string {
109	result := ""
110
111	for i, k := range keys {
112		if i > 0 {
113			result += ", "
114		}
115
116		result += k
117	}
118
119	return result
120}