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 all tracked project directories",
17 Long: `List all directories where Crush has been used.
18This includes the working directory, data directory path, and last accessed time.`,
19 Example: `
20# List all projects in a table
21crush projects
22
23# Output as JSON
24crush projects --json
25 `,
26 RunE: func(cmd *cobra.Command, args []string) error {
27 jsonOutput, _ := cmd.Flags().GetBool("json")
28
29 projectList, err := projects.List()
30 if err != nil {
31 return err
32 }
33
34 if jsonOutput {
35 output := struct {
36 Projects []projects.Project `json:"projects"`
37 }{Projects: projectList}
38
39 data, err := json.Marshal(output)
40 if err != nil {
41 return err
42 }
43 cmd.Println(string(data))
44 return nil
45 }
46
47 if len(projectList) == 0 {
48 cmd.Println("No projects tracked yet.")
49 return nil
50 }
51
52 if term.IsTerminal(os.Stdout.Fd()) {
53 // We're in a TTY: make it fancy.
54 t := table.New().
55 Border(lipgloss.RoundedBorder()).
56 StyleFunc(func(row, col int) lipgloss.Style {
57 return lipgloss.NewStyle().Padding(0, 2)
58 }).
59 Headers("Path", "Data Dir", "Last Accessed")
60
61 for _, p := range projectList {
62 t.Row(p.Path, p.DataDir, p.LastAccessed.Local().Format("2006-01-02 15:04"))
63 }
64 lipgloss.Println(t)
65 return nil
66 }
67
68 // Not a TTY: plain output
69 for _, p := range projectList {
70 cmd.Printf("%s\t%s\t%s\n", p.Path, p.DataDir, p.LastAccessed.Format("2006-01-02T15:04:05Z07:00"))
71 }
72 return nil
73 },
74}
75
76func init() {
77 projectsCmd.Flags().Bool("json", false, "Output as JSON")
78}