From 57fd39d84d0fe10f9b4ec05d0abf0e488b826cc8 Mon Sep 17 00:00:00 2001 From: bbedward Date: Sun, 19 Jul 2026 12:43:04 -0400 Subject: [PATCH] matugen: add config dirs to detection of presence related #2894 port 1.5 --- core/internal/matugen/matugen.go | 34 ++++++--- core/internal/matugen/matugen_test.go | 103 ++++++++++++++++++++++++-- 2 files changed, 120 insertions(+), 17 deletions(-) diff --git a/core/internal/matugen/matugen.go b/core/internal/matugen/matugen.go index 574db3f9d..cdd643228 100644 --- a/core/internal/matugen/matugen.go +++ b/core/internal/matugen/matugen.go @@ -44,6 +44,7 @@ type TemplateDef struct { ID string Commands []string Flatpaks []string + ConfigDirs []string ConfigFile string Kind TemplateKind RunUnconditionally bool @@ -60,9 +61,9 @@ var templateRegistry = []TemplateDef{ {ID: "firefox", Commands: []string{"firefox"}, ConfigFile: "firefox.toml"}, {ID: "pywalfox", Commands: []string{"pywalfox"}, ConfigFile: "pywalfox.toml"}, {ID: "zenbrowser", Commands: []string{"zen", "zen-browser", "zen-beta", "zen-twilight"}, Flatpaks: []string{"app.zen_browser.zen"}, ConfigFile: "zenbrowser.toml"}, - {ID: "vesktop", Commands: []string{"vesktop"}, Flatpaks: []string{"dev.vencord.Vesktop"}, ConfigFile: "vesktop.toml"}, - {ID: "vencord", Commands: []string{"discord", "Discord", "discord-canary", "DiscordCanary"}, Flatpaks: []string{"com.discordapp.Discord", "com.discordapp.DiscordCanary"}, ConfigFile: "vencord.toml"}, - {ID: "equibop", Commands: []string{"equibop"}, ConfigFile: "equibop.toml"}, + {ID: "vesktop", Commands: []string{"vesktop"}, Flatpaks: []string{"dev.vencord.Vesktop"}, ConfigDirs: []string{"vesktop"}, ConfigFile: "vesktop.toml"}, + {ID: "vencord", Commands: []string{"discord", "Discord", "discord-canary", "DiscordCanary"}, Flatpaks: []string{"com.discordapp.Discord", "com.discordapp.DiscordCanary"}, ConfigDirs: []string{"Vencord"}, ConfigFile: "vencord.toml"}, + {ID: "equibop", Commands: []string{"equibop"}, ConfigDirs: []string{"equibop"}, ConfigFile: "equibop.toml"}, {ID: "ghostty", Commands: []string{"ghostty"}, ConfigFile: "ghostty.toml", Kind: TemplateKindTerminal}, {ID: "kitty", Commands: []string{"kitty"}, ConfigFile: "kitty.toml", Kind: TemplateKindTerminal}, {ID: "foot", Commands: []string{"foot"}, ConfigFile: "foot.toml", Kind: TemplateKindTerminal}, @@ -459,9 +460,9 @@ output_path = '%s' case TemplateKindGTK: switch opts.Mode { case ColorModeLight: - appendConfig(opts, cfgFile, nil, nil, "gtk3-light.toml") + appendConfig(opts, cfgFile, nil, nil, nil, "gtk3-light.toml") default: - appendConfig(opts, cfgFile, nil, nil, "gtk3-dark.toml") + appendConfig(opts, cfgFile, nil, nil, nil, "gtk3-dark.toml") } case TemplateKindTerminal: appendTerminalConfig(opts, cfgFile, tmpDir, tmpl.Commands, tmpl.Flatpaks, tmpl.ConfigFile) @@ -474,10 +475,10 @@ output_path = '%s' appendVSCodeConfig(cfgFile, "vscode-insiders", filepath.Join(homeDir, ".vscode-insiders/extensions"), opts.ShellDir) case TemplateKindEmacs: if utils.EmacsConfigDir() != "" { - appendConfig(opts, cfgFile, tmpl.Commands, tmpl.Flatpaks, tmpl.ConfigFile) + appendConfig(opts, cfgFile, tmpl.Commands, tmpl.Flatpaks, tmpl.ConfigDirs, tmpl.ConfigFile) } default: - appendConfig(opts, cfgFile, tmpl.Commands, tmpl.Flatpaks, tmpl.ConfigFile) + appendConfig(opts, cfgFile, tmpl.Commands, tmpl.Flatpaks, tmpl.ConfigDirs, tmpl.ConfigFile) } } @@ -512,13 +513,14 @@ func appendConfig( cfgFile *os.File, checkCmd []string, checkFlatpaks []string, + checkConfigDirs []string, fileName string, ) { configPath := filepath.Join(opts.ShellDir, "matugen", "configs", fileName) if _, err := os.Stat(configPath); err != nil { return } - if !appExists(opts.AppChecker, checkCmd, checkFlatpaks) { + if !appExists(opts.AppChecker, checkCmd, checkFlatpaks) && !configDirExists(checkConfigDirs) { return } data, err := os.ReadFile(configPath) @@ -599,6 +601,20 @@ func templateSessionActive(tmpl TemplateDef) bool { return err == nil } +func configDirExists(names []string) bool { + configHome := utils.XDGConfigHome() + if configHome == "" { + return false + } + for _, name := range names { + info, err := os.Stat(filepath.Join(configHome, name)) + if err == nil && info.IsDir() { + return true + } + } + return false +} + func appExists(checker utils.AppChecker, checkCmd []string, checkFlatpaks []string) bool { // Both nil is treated as "skip check" / unconditionally run if checkCmd == nil && checkFlatpaks == nil { @@ -1076,7 +1092,7 @@ func CheckTemplates(checker utils.AppChecker) []TemplateCheck { case tmpl.Kind == TemplateKindEmacs: detected = appExists(checker, tmpl.Commands, tmpl.Flatpaks) && utils.EmacsConfigDir() != "" default: - detected = appExists(checker, tmpl.Commands, tmpl.Flatpaks) && templateSessionActive(tmpl) + detected = (appExists(checker, tmpl.Commands, tmpl.Flatpaks) || configDirExists(tmpl.ConfigDirs)) && templateSessionActive(tmpl) } checks = append(checks, TemplateCheck{ID: tmpl.ID, Detected: detected}) diff --git a/core/internal/matugen/matugen_test.go b/core/internal/matugen/matugen_test.go index 3420366b8..060a101aa 100644 --- a/core/internal/matugen/matugen_test.go +++ b/core/internal/matugen/matugen_test.go @@ -38,7 +38,7 @@ func TestAppendConfigBinaryExists(t *testing.T) { opts := &Options{ShellDir: shellDir, AppChecker: mockChecker} - appendConfig(opts, cfgFile, []string{"sh"}, nil, "test.toml") + appendConfig(opts, cfgFile, []string{"sh"}, nil, nil, "test.toml") cfgFile.Close() output, err := os.ReadFile(outFile) @@ -82,7 +82,7 @@ func TestAppendConfigBinaryDoesNotExist(t *testing.T) { opts := &Options{ShellDir: shellDir, AppChecker: mockChecker} - appendConfig(opts, cfgFile, []string{"nonexistent-binary-12345"}, []string{}, "test.toml") + appendConfig(opts, cfgFile, []string{"nonexistent-binary-12345"}, []string{}, nil, "test.toml") cfgFile.Close() output, err := os.ReadFile(outFile) @@ -122,7 +122,7 @@ func TestAppendConfigFlatpakExists(t *testing.T) { opts := &Options{ShellDir: shellDir, AppChecker: mockChecker} - appendConfig(opts, cfgFile, nil, []string{"app.zen_browser.zen"}, "test.toml") + appendConfig(opts, cfgFile, nil, []string{"app.zen_browser.zen"}, nil, "test.toml") cfgFile.Close() output, err := os.ReadFile(outFile) @@ -163,7 +163,7 @@ func TestAppendConfigFlatpakDoesNotExist(t *testing.T) { opts := &Options{ShellDir: shellDir, AppChecker: mockChecker} - appendConfig(opts, cfgFile, []string{}, []string{"com.nonexistent.flatpak"}, "test.toml") + appendConfig(opts, cfgFile, []string{}, []string{"com.nonexistent.flatpak"}, nil, "test.toml") cfgFile.Close() output, err := os.ReadFile(outFile) @@ -203,7 +203,7 @@ func TestAppendConfigBothExist(t *testing.T) { opts := &Options{ShellDir: shellDir, AppChecker: mockChecker} - appendConfig(opts, cfgFile, []string{"sh"}, []string{"app.zen_browser.zen"}, "test.toml") + appendConfig(opts, cfgFile, []string{"sh"}, []string{"app.zen_browser.zen"}, nil, "test.toml") cfgFile.Close() output, err := os.ReadFile(outFile) @@ -244,7 +244,7 @@ func TestAppendConfigNeitherExists(t *testing.T) { opts := &Options{ShellDir: shellDir, AppChecker: mockChecker} - appendConfig(opts, cfgFile, []string{"nonexistent-binary-12345"}, []string{"com.nonexistent.flatpak"}, "test.toml") + appendConfig(opts, cfgFile, []string{"nonexistent-binary-12345"}, []string{"com.nonexistent.flatpak"}, nil, "test.toml") cfgFile.Close() output, err := os.ReadFile(outFile) @@ -281,7 +281,7 @@ func TestAppendConfigNoChecks(t *testing.T) { opts := &Options{ShellDir: shellDir} - appendConfig(opts, cfgFile, nil, nil, "test.toml") + appendConfig(opts, cfgFile, nil, nil, nil, "test.toml") cfgFile.Close() output, err := os.ReadFile(outFile) @@ -312,7 +312,7 @@ func TestAppendConfigFileDoesNotExist(t *testing.T) { opts := &Options{ShellDir: shellDir} - appendConfig(opts, cfgFile, nil, nil, "nonexistent.toml") + appendConfig(opts, cfgFile, nil, nil, nil, "nonexistent.toml") cfgFile.Close() output, err := os.ReadFile(outFile) @@ -487,3 +487,90 @@ func TestBuildMergedConfigSkipsMangowcWithoutActiveSession(t *testing.T) { } assert.NotContains(t, string(output), "[templates.dmsmango]") } + +func TestAppendConfigConfigDirExists(t *testing.T) { + tempDir := t.TempDir() + + shellDir := filepath.Join(tempDir, "shell") + configsDir := filepath.Join(shellDir, "matugen", "configs") + if err := os.MkdirAll(configsDir, 0o755); err != nil { + t.Fatalf("failed to create configs dir: %v", err) + } + + testConfig := "vencord config content" + if err := os.WriteFile(filepath.Join(configsDir, "vencord.toml"), []byte(testConfig), 0o644); err != nil { + t.Fatalf("failed to write config: %v", err) + } + + configHome := filepath.Join(tempDir, "config") + if err := os.MkdirAll(filepath.Join(configHome, "Vencord"), 0o755); err != nil { + t.Fatalf("failed to create Vencord config dir: %v", err) + } + t.Setenv("XDG_CONFIG_HOME", configHome) + + outFile := filepath.Join(tempDir, "output.toml") + cfgFile, err := os.Create(outFile) + if err != nil { + t.Fatalf("failed to create output file: %v", err) + } + defer cfgFile.Close() + + mockChecker := mocks_utils.NewMockAppChecker(t) + mockChecker.EXPECT().AnyCommandExists("nonexistent-binary-12345").Return(false) + mockChecker.EXPECT().AnyFlatpakExists("com.nonexistent.flatpak").Return(false) + + opts := &Options{ShellDir: shellDir, AppChecker: mockChecker} + + appendConfig(opts, cfgFile, []string{"nonexistent-binary-12345"}, []string{"com.nonexistent.flatpak"}, []string{"Vencord"}, "vencord.toml") + + cfgFile.Close() + output, err := os.ReadFile(outFile) + if err != nil { + t.Fatalf("failed to read output: %v", err) + } + + assert.Equal(t, testConfig+"\n", string(output)) +} + +func TestAppendConfigConfigDirDoesNotExist(t *testing.T) { + tempDir := t.TempDir() + + shellDir := filepath.Join(tempDir, "shell") + configsDir := filepath.Join(shellDir, "matugen", "configs") + if err := os.MkdirAll(configsDir, 0o755); err != nil { + t.Fatalf("failed to create configs dir: %v", err) + } + + if err := os.WriteFile(filepath.Join(configsDir, "vencord.toml"), []byte("vencord config content"), 0o644); err != nil { + t.Fatalf("failed to write config: %v", err) + } + + configHome := filepath.Join(tempDir, "config") + if err := os.MkdirAll(configHome, 0o755); err != nil { + t.Fatalf("failed to create config home: %v", err) + } + t.Setenv("XDG_CONFIG_HOME", configHome) + + outFile := filepath.Join(tempDir, "output.toml") + cfgFile, err := os.Create(outFile) + if err != nil { + t.Fatalf("failed to create output file: %v", err) + } + defer cfgFile.Close() + + mockChecker := mocks_utils.NewMockAppChecker(t) + mockChecker.EXPECT().AnyCommandExists("nonexistent-binary-12345").Return(false) + mockChecker.EXPECT().AnyFlatpakExists("com.nonexistent.flatpak").Return(false) + + opts := &Options{ShellDir: shellDir, AppChecker: mockChecker} + + appendConfig(opts, cfgFile, []string{"nonexistent-binary-12345"}, []string{"com.nonexistent.flatpak"}, []string{"Vencord"}, "vencord.toml") + + cfgFile.Close() + output, err := os.ReadFile(outFile) + if err != nil { + t.Fatalf("failed to read output: %v", err) + } + + assert.Empty(t, string(output)) +}