on main help sign in
refactor: centralize user config path in a single func `home.Config()` (#2542)
commit206aecfbfdc9adcb854f38d1addeb7db959032cd authorAndrey Nering <andreynering@users.noreply.github.com> dateWed 1 Apr 2026, 14:46 (7 months ago) parent782d4dc
4 files changed+25−56
internal/commands/commands.go+11−35 internal/config/load.go+3−11 internal/fsext/ls.go+2−10 internal/home/home.go+9
internal/commands/commands.go+11−35
@@ -91,31 +91,20 @@ func LoadMCPPrompts() ([]MCPPrompt, error) {
9191}
9292
9393func buildCommandSources(cfg *config.Config) []commandSource {
94− var sources []commandSource
95−
96− // XDG config directory
97− if dir := getXDGCommandsDir(); dir != "" {
98− sources = append(sources, commandSource{
99− path: dir,
94+ return []commandSource{
95+ {
96+ path: filepath.Join(home.Config(), "crush", "commands"),
10097 prefix: userCommandPrefix,
101− })
102− }
103−
104− // Home directory
105− if home := home.Dir(); home != "" {
106− sources = append(sources, commandSource{
107− path: filepath.Join(home, ".crush", "commands"),
98+ },
99+ {
100+ path: filepath.Join(home.Dir(), ".crush", "commands"),
108101 prefix: userCommandPrefix,
109− })
102+ },
103+ {
104+ path: filepath.Join(cfg.Options.DataDirectory, "commands"),
105+ prefix: projectCommandPrefix,
106+ },
110107 }
111−
112− // Project directory
113− sources = append(sources, commandSource{
114− path: filepath.Join(cfg.Options.DataDirectory, "commands"),
115− prefix: projectCommandPrefix,
116− })
117−
118− return sources
119108}
120109
121110func loadAll(sources []commandSource) ([]CustomCommand, error) {
@@ -204,19 +193,6 @@ func buildCommandID(path, baseDir, prefix string) string {
204193 return prefix + strings.Join(parts, ":")
205194}
206195
207−func getXDGCommandsDir() string {
208− xdgHome := os.Getenv("XDG_CONFIG_HOME")
209− if xdgHome == "" {
210− if home := home.Dir(); home != "" {
211− xdgHome = filepath.Join(home, ".config")
212− }
213− }
214− if xdgHome != "" {
215− return filepath.Join(xdgHome, "crush", "commands")
216− }
217− return ""
218−}
219−
220196func isMarkdownFile(name string) bool {
221197 return strings.HasSuffix(strings.ToLower(name), ".md")
222198}
internal/config/load.go+3−11
@@ -746,10 +746,7 @@ func GlobalConfig() string {
746746 if crushGlobal := os.Getenv("CRUSH_GLOBAL_CONFIG"); crushGlobal != "" {
747747 return filepath.Join(crushGlobal, fmt.Sprintf("%s.json", appName))
748748 }
749− if xdgConfigHome := os.Getenv("XDG_CONFIG_HOME"); xdgConfigHome != "" {
750− return filepath.Join(xdgConfigHome, appName, fmt.Sprintf("%s.json", appName))
751− }
752− return filepath.Join(home.Dir(), ".config", appName, fmt.Sprintf("%s.json", appName))
749+ return filepath.Join(home.Config(), appName, fmt.Sprintf("%s.json", appName))
753750}
754751
755752// GlobalConfigData returns the path to the main data directory for the application.
@@ -799,14 +796,9 @@ func GlobalSkillsDirs() []string {
799796 return []string{crushSkills}
800797 }
801798
802− configHome := cmp.Or(
803− os.Getenv("XDG_CONFIG_HOME"),
804− filepath.Join(home.Dir(), ".config"),
805− )
806−
807799 paths := []string{
808− filepath.Join(configHome, appName, "skills"),
809− filepath.Join(configHome, "agents", "skills"),
800+ filepath.Join(home.Config(), appName, "skills"),
801+ filepath.Join(home.Config(), "agents", "skills"),
810802 }
811803
812804 // On Windows, also load from app data on top of `$HOME/.config/crush`.
internal/fsext/ls.go+2−10
@@ -91,13 +91,9 @@ var gitGlobalIgnorePatterns = sync.OnceValue(func() []gitignore.Pattern {
9191 return nil
9292 }
9393
94− configPath := cmp.Or(
95− os.Getenv("XDG_CONFIG_HOME"),
96− filepath.Join(home.Dir(), ".config"),
97− )
9894 excludesFilePath := cmp.Or(
9995 cfg.Raw.Section("core").Options.Get("excludesfile"),
100− filepath.Join(configPath, "git", "ignore"),
96+ filepath.Join(home.Config(), "git", "ignore"),
10197 )
10298 excludesFilePath = home.Long(excludesFilePath)
10399
@@ -115,11 +111,7 @@ var gitGlobalIgnorePatterns = sync.OnceValue(func() []gitignore.Pattern {
115111// crushGlobalIgnorePatterns returns patterns from the user's
116112// ~/.config/crush/ignore file.
117113var crushGlobalIgnorePatterns = sync.OnceValue(func() []gitignore.Pattern {
118− configPath := cmp.Or(
119− os.Getenv("XDG_CONFIG_HOME"),
120− filepath.Join(home.Dir(), ".config"),
121− )
122− name := filepath.Join(configPath, "crush", "ignore")
114+ name := filepath.Join(home.Config(), "crush", "ignore")
123115 bts, err := os.ReadFile(name)
124116 if err != nil {
125117 if !os.IsNotExist(err) {
internal/home/home.go+9
@@ -2,6 +2,7 @@
22package home
33
44import (
5+ "cmp"
56 "log/slog"
67 "os"
78 "path/filepath"
@@ -21,6 +22,14 @@ func Dir() string {
2122 return homedir
2223}
2324
25+// Config returns the user config directory.
26+func Config() string {
27+ return cmp.Or(
28+ os.Getenv("XDG_CONFIG_HOME"),
29+ filepath.Join(Dir(), ".config"),
30+ )
31+}
32+
2433// Short replaces the actual home path from [Dir] with `~`.
2534func Short(p string) string {
2635 if homedir == "" || !strings.HasPrefix(p, homedir) {