1package cmd
2
3import (
4 "encoding/json"
5 "os"
6
7 "charm.land/lipgloss/v2"
8 "charm.land/lipgloss/v2/table"
9 "github.com/charmbracelet/crush/internal/projects"
10 "github.com/charmbracelet/x/term"
11 "github.com/spf13/cobra"
12)
13
14var projectsCmd = &cobra.Command{
15 Use: "projects",
16 Short: "List project directories",
17 Long: "List directories where Crush project data is known to exist",
18 Example: `
19# List all projects in a table
20crush projects
21
22# Output projects data as JSON
23crush projects --json
24 `,
25 RunE: func(cmd *cobra.Command, args []string) error {
26 jsonOutput, _ := cmd.Flags().GetBool("json")
27
28 projectList, err := projects.List()
29 if err != nil {
30 return err
31 }
32
33 if jsonOutput {
34 output := struct {
35 Projects []projects.Project `json:"projects"`
36 }{Projects: projectList}
37
38 data, err := json.Marshal(output)
39 if err != nil {
40 return err
41 }
42 cmd.Println(string(data))
43 return nil
44 }
45
46 if len(projectList) == 0 {
47 cmd.Println("No projects tracked yet.")
48 return nil
49 }
50
51 if term.IsTerminal(os.Stdout.Fd()) {
52 // We're in a TTY: make it fancy.
53 t := table.New().
54 Border(lipgloss.RoundedBorder()).
55 StyleFunc(func(row, col int) lipgloss.Style {
56 return lipgloss.NewStyle().Padding(0, 2)
57 }).
58 Headers("Path", "Data Dir", "Last Accessed")
59
60 for _, p := range projectList {
61 t.Row(p.Path, p.DataDir, p.LastAccessed.Local().Format("2006-01-02 15:04"))
62 }
63 lipgloss.Println(t)
64 return nil
65 }
66
67 // Not a TTY: plain output
68 for _, p := range projectList {
69 cmd.Printf("%s\t%s\t%s\n", p.Path, p.DataDir, p.LastAccessed.Format("2006-01-02T15:04:05Z07:00"))
70 }
71 return nil
72 },
73}
74
75func init() {
76 projectsCmd.Flags().Bool("json", false, "Output as JSON")
77}