From b83256c83a3abf7e6c6cd61c9bbf4c50f6b7d9ff Mon Sep 17 00:00:00 2001 From: bbedward Date: Tue, 24 Feb 2026 13:27:48 -0500 Subject: [PATCH] matugen: skip theme refreshes if no colors changed --- core/cmd/dms/commands_matugen.go | 29 +++++++++++++++---- core/internal/matugen/matugen.go | 45 +++++++++++++++++++---------- core/internal/matugen/queue.go | 10 +++++-- quickshell/Services/NiriService.qml | 2 +- 4 files changed, 61 insertions(+), 25 deletions(-) diff --git a/core/cmd/dms/commands_matugen.go b/core/cmd/dms/commands_matugen.go index b6b27117..f3809135 100644 --- a/core/cmd/dms/commands_matugen.go +++ b/core/cmd/dms/commands_matugen.go @@ -3,7 +3,9 @@ package main import ( "context" "encoding/json" + "errors" "fmt" + "os" "time" "github.com/AvengeMedia/DankMaterialShell/core/internal/log" @@ -95,7 +97,11 @@ func buildMatugenOptions(cmd *cobra.Command) matugen.Options { func runMatugenGenerate(cmd *cobra.Command, args []string) { opts := buildMatugenOptions(cmd) - if err := matugen.Run(opts); err != nil { + err := matugen.Run(opts) + switch { + case errors.Is(err, matugen.ErrNoChanges): + os.Exit(2) + case err != nil: log.Fatalf("Theme generation failed: %v", err) } } @@ -129,7 +135,11 @@ func runMatugenQueue(cmd *cobra.Command, args []string) { if !wait { if err := sendServerRequestFireAndForget(request); err != nil { log.Info("Server unavailable, running synchronously") - if err := matugen.Run(opts); err != nil { + err := matugen.Run(opts) + switch { + case errors.Is(err, matugen.ErrNoChanges): + os.Exit(2) + case err != nil: log.Fatalf("Theme generation failed: %v", err) } return @@ -146,11 +156,15 @@ func runMatugenQueue(cmd *cobra.Command, args []string) { resp, ok := tryServerRequest(request) if !ok { log.Info("Server unavailable, running synchronously") - if err := matugen.Run(opts); err != nil { + err := matugen.Run(opts) + switch { + case errors.Is(err, matugen.ErrNoChanges): + resultCh <- matugen.ErrNoChanges + case err != nil: resultCh <- err - return + default: + resultCh <- nil } - resultCh <- nil return } if resp.Error != "" { @@ -162,7 +176,10 @@ func runMatugenQueue(cmd *cobra.Command, args []string) { select { case err := <-resultCh: - if err != nil { + switch { + case errors.Is(err, matugen.ErrNoChanges): + os.Exit(2) + case err != nil: log.Fatalf("Theme generation failed: %v", err) } fmt.Println("Theme generation completed") diff --git a/core/internal/matugen/matugen.go b/core/internal/matugen/matugen.go index b77c4e4c..b8e43048 100644 --- a/core/internal/matugen/matugen.go +++ b/core/internal/matugen/matugen.go @@ -1,7 +1,9 @@ package matugen import ( + "bytes" "encoding/json" + "errors" "fmt" "math" "os" @@ -19,6 +21,8 @@ import ( "github.com/lucasb-eyer/go-colorful" ) +var ErrNoChanges = errors.New("no color changes") + type ColorMode string const ( @@ -160,39 +164,45 @@ func Run(opts Options) error { log.Infof("Building theme: %s %s (%s)", opts.Kind, opts.Value, opts.Mode) - buildErr := buildOnce(&opts) + changed, buildErr := buildOnce(&opts) + if buildErr != nil { + return buildErr + } + + if !changed { + log.Info("No color changes detected, skipping refresh") + return ErrNoChanges + } if opts.SyncModeWithPortal { syncColorScheme(opts.Mode) } - if buildErr != nil { - return buildErr - } - log.Info("Done") return nil } -func buildOnce(opts *Options) error { +func buildOnce(opts *Options) (bool, error) { cfgFile, err := os.CreateTemp("", "matugen-config-*.toml") if err != nil { - return fmt.Errorf("failed to create temp config: %w", err) + return false, fmt.Errorf("failed to create temp config: %w", err) } defer os.Remove(cfgFile.Name()) defer cfgFile.Close() tmpDir, err := os.MkdirTemp("", "matugen-templates-*") if err != nil { - return fmt.Errorf("failed to create temp dir: %w", err) + return false, fmt.Errorf("failed to create temp dir: %w", err) } defer os.RemoveAll(tmpDir) if err := buildMergedConfig(opts, cfgFile, tmpDir); err != nil { - return fmt.Errorf("failed to build config: %w", err) + return false, fmt.Errorf("failed to build config: %w", err) } cfgFile.Close() + oldColors, _ := os.ReadFile(opts.ColorsOutput()) + var primaryDark, primaryLight, surface string var dank16JSON string var importArgs []string @@ -204,7 +214,7 @@ func buildOnce(opts *Options) error { surface = extractNestedColor(opts.StockColors, "surface", "dark") if primaryDark == "" { - return fmt.Errorf("failed to extract primary dark from stock colors") + return false, fmt.Errorf("failed to extract primary dark from stock colors") } if primaryLight == "" { primaryLight = primaryDark @@ -218,14 +228,14 @@ func buildOnce(opts *Options) error { args := []string{"color", "hex", primaryDark, "-m", string(opts.Mode), "-t", opts.MatugenType, "-c", cfgFile.Name()} args = append(args, importArgs...) if err := runMatugen(args); err != nil { - return err + return false, err } } else { log.Infof("Using dynamic theme from %s: %s", opts.Kind, opts.Value) matJSON, err := runMatugenDryRun(opts) if err != nil { - return fmt.Errorf("matugen dry-run failed: %w", err) + return false, fmt.Errorf("matugen dry-run failed: %w", err) } primaryDark = extractMatugenColor(matJSON, "primary", "dark") @@ -233,7 +243,7 @@ func buildOnce(opts *Options) error { surface = extractMatugenColor(matJSON, "surface", "dark") if primaryDark == "" { - return fmt.Errorf("failed to extract primary color") + return false, fmt.Errorf("failed to extract primary color") } if primaryLight == "" { primaryLight = primaryDark @@ -254,10 +264,15 @@ func buildOnce(opts *Options) error { args = append(args, "-m", string(opts.Mode), "-t", opts.MatugenType, "-c", cfgFile.Name()) args = append(args, importArgs...) if err := runMatugen(args); err != nil { - return err + return false, err } } + newColors, _ := os.ReadFile(opts.ColorsOutput()) + if bytes.Equal(oldColors, newColors) && len(oldColors) > 0 { + return false, nil + } + if isDMSGTKActive(opts.ConfigDir) { switch opts.Mode { case ColorModeLight: @@ -275,7 +290,7 @@ func buildOnce(opts *Options) error { signalTerminals(opts) - return nil + return true, nil } func buildMergedConfig(opts *Options, cfgFile *os.File, tmpDir string) error { diff --git a/core/internal/matugen/queue.go b/core/internal/matugen/queue.go index ad6a0971..38cf72ac 100644 --- a/core/internal/matugen/queue.go +++ b/core/internal/matugen/queue.go @@ -2,6 +2,7 @@ package matugen import ( "context" + "errors" "sync" "github.com/AvengeMedia/DankMaterialShell/core/internal/log" @@ -93,10 +94,13 @@ func (q *Queue) runWorker() { err := Run(job.Options) var result Result - if err != nil { - result = Result{Success: false, Error: err} - } else { + switch { + case err == nil: result = Result{Success: true} + case errors.Is(err, ErrNoChanges): + result = Result{Success: true} + default: + result = Result{Success: false, Error: err} } q.finishJob(result) diff --git a/quickshell/Services/NiriService.qml b/quickshell/Services/NiriService.qml index be695f3a..d24ffeb3 100644 --- a/quickshell/Services/NiriService.qml +++ b/quickshell/Services/NiriService.qml @@ -66,7 +66,7 @@ Singleton { Timer { id: suppressResetTimer - interval: 2000 + interval: 5000 onTriggered: root.matugenSuppression = false }