refactor: centralize user config path in a single func `home.Config()` (#2542)

Andrey Nering created

Change summary

internal/commands/commands.go | 46 ++++++++----------------------------
internal/config/load.go       | 14 ++--------
internal/fsext/ls.go          | 12 +--------
internal/home/home.go         |  9 +++++++
4 files changed, 25 insertions(+), 56 deletions(-)

Detailed changes

internal/commands/commands.go 🔗

@@ -91,31 +91,20 @@ func LoadMCPPrompts() ([]MCPPrompt, error) {
 }
 
 func buildCommandSources(cfg *config.Config) []commandSource {
-	var sources []commandSource
-
-	// XDG config directory
-	if dir := getXDGCommandsDir(); dir != "" {
-		sources = append(sources, commandSource{
-			path:   dir,
+	return []commandSource{
+		{
+			path:   filepath.Join(home.Config(), "crush", "commands"),
 			prefix: userCommandPrefix,
-		})
-	}
-
-	// Home directory
-	if home := home.Dir(); home != "" {
-		sources = append(sources, commandSource{
-			path:   filepath.Join(home, ".crush", "commands"),
+		},
+		{
+			path:   filepath.Join(home.Dir(), ".crush", "commands"),
 			prefix: userCommandPrefix,
-		})
+		},
+		{
+			path:   filepath.Join(cfg.Options.DataDirectory, "commands"),
+			prefix: projectCommandPrefix,
+		},
 	}
-
-	// Project directory
-	sources = append(sources, commandSource{
-		path:   filepath.Join(cfg.Options.DataDirectory, "commands"),
-		prefix: projectCommandPrefix,
-	})
-
-	return sources
 }
 
 func loadAll(sources []commandSource) ([]CustomCommand, error) {
@@ -204,19 +193,6 @@ func buildCommandID(path, baseDir, prefix string) string {
 	return prefix + strings.Join(parts, ":")
 }
 
-func getXDGCommandsDir() string {
-	xdgHome := os.Getenv("XDG_CONFIG_HOME")
-	if xdgHome == "" {
-		if home := home.Dir(); home != "" {
-			xdgHome = filepath.Join(home, ".config")
-		}
-	}
-	if xdgHome != "" {
-		return filepath.Join(xdgHome, "crush", "commands")
-	}
-	return ""
-}
-
 func isMarkdownFile(name string) bool {
 	return strings.HasSuffix(strings.ToLower(name), ".md")
 }

internal/config/load.go 🔗

@@ -746,10 +746,7 @@ func GlobalConfig() string {
 	if crushGlobal := os.Getenv("CRUSH_GLOBAL_CONFIG"); crushGlobal != "" {
 		return filepath.Join(crushGlobal, fmt.Sprintf("%s.json", appName))
 	}
-	if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" {
-		return filepath.Join(xdgConfigHome, appName, fmt.Sprintf("%s.json", appName))
-	}
-	return filepath.Join(home.Dir(), ".config", appName, fmt.Sprintf("%s.json", appName))
+	return filepath.Join(home.Config(), appName, fmt.Sprintf("%s.json", appName))
 }
 
 // GlobalConfigData returns the path to the main data directory for the application.
@@ -799,14 +796,9 @@ func GlobalSkillsDirs() []string {
 		return []string{crushSkills}
 	}
 
-	configHome := cmp.Or(
-		os.Getenv("XDG_CONFIG_HOME"),
-		filepath.Join(home.Dir(), ".config"),
-	)
-
 	paths := []string{
-		filepath.Join(configHome, appName, "skills"),
-		filepath.Join(configHome, "agents", "skills"),
+		filepath.Join(home.Config(), appName, "skills"),
+		filepath.Join(home.Config(), "agents", "skills"),
 	}
 
 	// On Windows, also load from app data on top of `$HOME/.config/crush`.

internal/fsext/ls.go 🔗

@@ -91,13 +91,9 @@ var gitGlobalIgnorePatterns = sync.OnceValue(func() []gitignore.Pattern {
 		return nil
 	}
 
-	configPath := cmp.Or(
-		os.Getenv("XDG_CONFIG_HOME"),
-		filepath.Join(home.Dir(), ".config"),
-	)
 	excludesFilePath := cmp.Or(
 		cfg.Raw.Section("core").Options.Get("excludesfile"),
-		filepath.Join(configPath, "git", "ignore"),
+		filepath.Join(home.Config(), "git", "ignore"),
 	)
 	excludesFilePath = home.Long(excludesFilePath)
 
@@ -115,11 +111,7 @@ var gitGlobalIgnorePatterns = sync.OnceValue(func() []gitignore.Pattern {
 // crushGlobalIgnorePatterns returns patterns from the user's
 // ~/.config/crush/ignore file.
 var crushGlobalIgnorePatterns = sync.OnceValue(func() []gitignore.Pattern {
-	configPath := cmp.Or(
-		os.Getenv("XDG_CONFIG_HOME"),
-		filepath.Join(home.Dir(), ".config"),
-	)
-	name := filepath.Join(configPath, "crush", "ignore")
+	name := filepath.Join(home.Config(), "crush", "ignore")
 	bts, err := os.ReadFile(name)
 	if err != nil {
 		if !os.IsNotExist(err) {

internal/home/home.go 🔗

@@ -2,6 +2,7 @@
 package home
 
 import (
+	"cmp"
 	"log/slog"
 	"os"
 	"path/filepath"
@@ -21,6 +22,14 @@ func Dir() string {
 	return homedir
 }
 
+// Config returns the user config directory.
+func Config() string {
+	return cmp.Or(
+		os.Getenv("XDG_CONFIG_HOME"),
+		filepath.Join(Dir(), ".config"),
+	)
+}
+
 // Short replaces the actual home path from [Dir] with `~`.
 func Short(p string) string {
 	if homedir == "" || !strings.HasPrefix(p, homedir) {