@@ -1,110 +1,91 @@
6 "path/filepath"
5 "path/filepath"
9 "charm.land/lipgloss/v2"
8 "charm.land/lipgloss/v2"
10− "charm.land/lipgloss/v2/table"
11 "github.com/charmbracelet/crush/internal/config"
9 "github.com/charmbracelet/crush/internal/config"
10+ "github.com/charmbracelet/x/exp/charmtone"
12 "github.com/charmbracelet/x/term"
11 "github.com/charmbracelet/x/term"
13 "github.com/spf13/cobra"
12 "github.com/spf13/cobra"
16var dirsCmd = &cobra.Command{
15var dirsCmd = &cobra.Command{
17 Use: "dirs",
16 Use: "dirs",
18− Short: "Print directories used by Crush",
17+ Short: "Show config and data directories",
19− Long: `Print the directories where Crush stores its configuration and data files.
18+ Long: `Show where Crush stores its configuration and data,
20−This includes the global configuration directory and data directory.`,
19+including any project-level config files discovered
20+from the current directory up to the project root.`,
21 Example: `
21 Example: `
22−# Print all global directories
22+# Show all directories
25−# Print data directory and all project specific config directories
28−# Print only global config directory
31−# Print only project specific config directories
34−# Print only the data directory
37− RunE: func(cmd *cobra.Command, args []string) error {
25+ Run: func(cmd *cobra.Command, args []string) {
38− dirs, err := configDirs(cmd)
26+ entries := collectDirs(cmd)
40− return fmt.Errorf("cannot collect config directories: %w", err)
43 if term.IsTerminal(os.Stdout.Fd()) {
27 if term.IsTerminal(os.Stdout.Fd()) {
44− // We're in a TTY: make it fancy.
28+ printDirs(cmd, entries)
46− Border(lipgloss.RoundedBorder()).
47− StyleFunc(func(row, col int) lipgloss.Style {
48− return lipgloss.NewStyle().Padding(0, 2)
51− Row("Data", filepath.Dir(config.GlobalConfigData()))
55− // Not a TTY.
31+ for _, e := range entries {
56− cmd.Println(dirs)
32+ cmd.Println(e)
57− cmd.Println(filepath.Dir(config.GlobalConfigData()))
63−var configDirCmd = &cobra.Command{
65− Short: "Print the configuration directory used by Crush",
66− RunE: func(cmd *cobra.Command, args []string) error {
67− dirs, err := configDirs(cmd)
69− return fmt.Errorf("cannot collect config directories: %w", err)
76−var dataDirCmd = &cobra.Command{
78− Short: "Print the datauration directory used by Crush",
79− Run: func(cmd *cobra.Command, args []string) {
37+func collectDirs(cmd *cobra.Command) []string {
80− cmd.Println(filepath.Dir(config.GlobalConfigData()))
38+ var dirs []string
84−// configDirs returns formatted string with one or more project config paths
85−func configDirs(cmd *cobra.Command) (string, error) {
86− configDir := filepath.Dir(config.GlobalConfig())
40+ dirs = append(dirs, filepath.Dir(config.GlobalConfig()))
87− if ok, _ := cmd.Flags().GetBool("project"); !ok {
41+ dirs = append(dirs, filepath.Dir(config.GlobalConfigData()))
88− return configDir, nil
91 cwd, err := ResolveCwd(cmd)
43 cwd, err := ResolveCwd(cmd)
92 if err != nil {
44 if err != nil {
93− return "", fmt.Errorf("cannot resolve current working directory: %w", err)
45+ return dirs
96− var sb strings.Builder
97− for i, path := range config.ProjectConfigs(cwd) {
48+ for _, p := range config.ProjectConfigs(cwd) {
98− if i > 0 {
49+ d := filepath.Dir(p)
99− sb.WriteByte('\n')
50+ // Skip global paths, already shown.
51+ if d == filepath.Dir(config.GlobalConfig()) || d == filepath.Dir(config.GlobalConfigData()) {
101− sb.WriteString(filepath.Dir(path))
54+ dirs = append(dirs, d)
103− return sb.String(), nil
57+ return dirs
106−func init() {
60+func printDirs(cmd *cobra.Command, dirs []string) {
107− dirsCmd.PersistentFlags().BoolP("project", "p", false, "Print project specific configs")
61+ labelStyle := lipgloss.NewStyle().Bold(true).Foreground(charmtone.Charple)
63+ labels := make([]string, len(dirs))
65+ for i := range dirs {
68+ if len(labels[i]) > longest {
69+ longest = len(labels[i])
73+ for i, d := range dirs {
74+ lipgloss.Println(labelStyle.Render(labels[i]) +
75+ strings.Repeat(" ", longest-len(labels[i])) +
79+ lipgloss.Println(lipgloss.NewStyle().Foreground(charmtone.Squid).Render("Configs merge from top to bottom"))
109− dirsCmd.AddCommand(configDirCmd, dataDirCmd)
82+func dirLabel(i int) string {