on main help sign in
refactor: centralize user config path in a single func `home.Config()` (#2542)
206aecfAndrey Nering
internal/commands/commands.go+11−35
@@ -91,31 +91,20 @@ func LoadMCPPrompts() ([]MCPPrompt, error) {
91}
91}
92
92
93func buildCommandSources(cfg *config.Config) []commandSource {
93func buildCommandSources(cfg *config.Config) []commandSource {
94− var sources []commandSource
94+ return []commandSource{
95−
95+ {
96− // XDG config directory
96+ path: filepath.Join(home.Config(), "crush", "commands"),
97− if dir := getXDGCommandsDir(); dir != "" {
98− sources = append(sources, commandSource{
99− path: dir,
100 prefix: userCommandPrefix,
97 prefix: userCommandPrefix,
101− })
98+ },
102− }
99+ {
103−
104− // Home directory
105− if home := home.Dir(); home != "" {
106− sources = append(sources, commandSource{
107− path: filepath.Join(home, ".crush", "commands"),
100+ path: filepath.Join(home.Dir(), ".crush", "commands"),
108 prefix: userCommandPrefix,
101 prefix: userCommandPrefix,
109− })
102+ },
103+ {
104+ path: filepath.Join(cfg.Options.DataDirectory, "commands"),
105+ prefix: projectCommandPrefix,
106+ },
110 }
107 }
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
119}
108}
120
109
121func loadAll(sources []commandSource) ([]CustomCommand, error) {
110func loadAll(sources []commandSource) ([]CustomCommand, error) {
@@ -204,19 +193,6 @@ func buildCommandID(path, baseDir, prefix string) string {
204 return prefix + strings.Join(parts, ":")
193 return prefix + strings.Join(parts, ":")
205}
194}
206
195
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−
220func isMarkdownFile(name string) bool {
196func isMarkdownFile(name string) bool {
221 return strings.HasSuffix(strings.ToLower(name), ".md")
197 return strings.HasSuffix(strings.ToLower(name), ".md")
222}
198}
internal/config/load.go+3−11
@@ -746,10 +746,7 @@ func GlobalConfig() string {
746 if crushGlobal := os.Getenv("CRUSH_GLOBAL_CONFIG"); crushGlobal != "" {
746 if crushGlobal := os.Getenv("CRUSH_GLOBAL_CONFIG"); crushGlobal != "" {
747 return filepath.Join(crushGlobal, fmt.Sprintf("%s.json", appName))
747 return filepath.Join(crushGlobal, fmt.Sprintf("%s.json", appName))
748 }
748 }
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))
753}
750}
754
751
755// GlobalConfigData returns the path to the main data directory for the application.
752// GlobalConfigData returns the path to the main data directory for the application.
@@ -799,14 +796,9 @@ func GlobalSkillsDirs() []string {
799 return []string{crushSkills}
796 return []string{crushSkills}
800 }
797 }
801
798
802− configHome := cmp.Or(
803− os.Getenv("XDG_CONFIG_HOME"),
804− filepath.Join(home.Dir(), ".config"),
805− )
806−
807 paths := []string{
799 paths := []string{
808− filepath.Join(configHome, appName, "skills"),
800+ filepath.Join(home.Config(), appName, "skills"),
809− filepath.Join(configHome, "agents", "skills"),
801+ filepath.Join(home.Config(), "agents", "skills"),
810 }
802 }
811
803
812 // On Windows, also load from app data on top of `$HOME/.config/crush`.
804 // 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 {
91 return nil
91 return nil
92 }
92 }
93
93
94− configPath := cmp.Or(
95− os.Getenv("XDG_CONFIG_HOME"),
96− filepath.Join(home.Dir(), ".config"),
97− )
98 excludesFilePath := cmp.Or(
94 excludesFilePath := cmp.Or(
99 cfg.Raw.Section("core").Options.Get("excludesfile"),
95 cfg.Raw.Section("core").Options.Get("excludesfile"),
100− filepath.Join(configPath, "git", "ignore"),
96+ filepath.Join(home.Config(), "git", "ignore"),
101 )
97 )
102 excludesFilePath = home.Long(excludesFilePath)
98 excludesFilePath = home.Long(excludesFilePath)
103
99
@@ -115,11 +111,7 @@ var gitGlobalIgnorePatterns = sync.OnceValue(func() []gitignore.Pattern {
115// crushGlobalIgnorePatterns returns patterns from the user's
111// crushGlobalIgnorePatterns returns patterns from the user's
116// ~/.config/crush/ignore file.
112// ~/.config/crush/ignore file.
117var crushGlobalIgnorePatterns = sync.OnceValue(func() []gitignore.Pattern {
113var crushGlobalIgnorePatterns = sync.OnceValue(func() []gitignore.Pattern {
118− configPath := cmp.Or(
119− os.Getenv("XDG_CONFIG_HOME"),
120− filepath.Join(home.Dir(), ".config"),
114+ name := filepath.Join(home.Config(), "crush", "ignore")
121− )
122− name := filepath.Join(configPath, "crush", "ignore")
123 bts, err := os.ReadFile(name)
115 bts, err := os.ReadFile(name)
124 if err != nil {
116 if err != nil {
125 if !os.IsNotExist(err) {
117 if !os.IsNotExist(err) {
internal/home/home.go+9
@@ -2,6 +2,7 @@
2package home
2package home
3
3
4import (
4import (
5+ "cmp"
5 "log/slog"
6 "log/slog"
6 "os"
7 "os"
7 "path/filepath"
8 "path/filepath"
@@ -21,6 +22,14 @@ func Dir() string {
21 return homedir
22 return homedir
22}
23}
23
24
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+
24// Short replaces the actual home path from [Dir] with `~`.
33// Short replaces the actual home path from [Dir] with `~`.
25func Short(p string) string {
34func Short(p string) string {
26 if homedir == "" || !strings.HasPrefix(p, homedir) {
35 if homedir == "" || !strings.HasPrefix(p, homedir) {