1package cmd
2
3import (
4 "os"
5 "path/filepath"
6 "strings"
7
8 "charm.land/lipgloss/v2"
9 "github.com/charmbracelet/crush/internal/config"
10 "github.com/charmbracelet/x/exp/charmtone"
11 "github.com/charmbracelet/x/term"
12 "github.com/spf13/cobra"
13)
14
15var dirsCmd = &cobra.Command{
16 Use: "dirs",
17 Short: "Show config and data directories",
18 Long: `Show where Crush stores its configuration and data,
19including any project-level config files discovered
20from the current directory up to the project root.`,
21 Example: `
22# Show all directories
23crush dirs
24 `,
25 Run: func(cmd *cobra.Command, args []string) {
26 entries := collectDirs(cmd)
27 if term.IsTerminal(os.Stdout.Fd()) {
28 printDirs(cmd, entries)
29 return
30 }
31 for _, e := range entries {
32 cmd.Println(e)
33 }
34 },
35}
36
37func collectDirs(cmd *cobra.Command) []string {
38 var dirs []string
39
40 dirs = append(dirs, filepath.Dir(config.GlobalConfig()))
41 dirs = append(dirs, filepath.Dir(config.GlobalConfigData()))
42
43 cwd, err := ResolveCwd(cmd)
44 if err != nil {
45 return dirs
46 }
47
48 for _, p := range config.ProjectConfigs(cwd) {
49 d := filepath.Dir(p)
50 // Skip global paths, already shown.
51 if d == filepath.Dir(config.GlobalConfig()) || d == filepath.Dir(config.GlobalConfigData()) {
52 continue
53 }
54 dirs = append(dirs, d)
55 }
56
57 return dirs
58}
59
60func printDirs(cmd *cobra.Command, dirs []string) {
61 labelStyle := lipgloss.NewStyle().Bold(true).Foreground(charmtone.Charple)
62
63 labels := make([]string, len(dirs))
64 longest := 0
65 for i := range dirs {
66 l := dirLabel(i)
67 labels[i] = l + ":"
68 if len(labels[i]) > longest {
69 longest = len(labels[i])
70 }
71 }
72
73 for i, d := range dirs {
74 lipgloss.Println(labelStyle.Render(labels[i]) +
75 strings.Repeat(" ", longest-len(labels[i])) +
76 " " + d)
77 }
78
79 lipgloss.Println(lipgloss.NewStyle().Foreground(charmtone.Squid).Render("Configs merge from top to bottom"))
80}
81
82func dirLabel(i int) string {
83 switch i {
84 case 0:
85 return "Config"
86 case 1:
87 return "Data"
88 default:
89 return "Project"
90 }
91}