@@ -11,7 +11,8 @@ import (
1111)
1212
1313type Config struct {
14- D4S D4SConfig `yaml:"d4s"`
14+ D4S D4SConfig `yaml:"d4s"`
15+ sourcePath string
1516}
1617
1718type D4SConfig struct {
@@ -179,11 +180,24 @@ func ensureConfigDirs() {
179180 _ = os .MkdirAll (filepath .Join (dir , "skins" ), 0o755 )
180181}
181182
183+ func parse (data []byte , configPath string ) (* Config , error ) {
184+ cfg := DefaultConfig ()
185+ if err := yaml .Unmarshal (data , cfg ); err != nil {
186+ return nil , fmt .Errorf ("parse config %q: %w" , configPath , err )
187+ }
188+
189+ // Enforce minimum refresh rate
190+ if cfg .D4S .RefreshRate < 2.0 && cfg .D4S .RefreshRate > 0 {
191+ cfg .D4S .RefreshRate = 2.0
192+ }
193+
10BC8
194+ return cfg , nil
195+ }
196+
182197// Load reads the config from $XDG_CONFIG_HOME/d4s/config.yaml.
183198// If the file doesn't exist or can't be parsed, defaults are returned.
184199func Load () * Config {
185200 cfg := DefaultConfig ()
186-
187201 dir := configDir ()
188202 if dir == "" {
189203 return cfg
@@ -202,27 +216,50 @@ func Load() *Config {
202216 }
203217 }
204218
205- // Parse into a fresh config so we can detect which fields were explicitly set
206- parsed := DefaultConfig ()
207- if err := yaml .Unmarshal (data , parsed ); err != nil {
208- fmt .Fprintf (os .Stderr , "d4s: warning: failed to parse %s: %v\n " , configPath , err )
219+ loaded , err := parse (data , configPath )
220+ if err != nil {
221+ fmt .Fprintf (os .Stderr , "d4s: warning: %v\n " , err )
209222 return cfg
210223 }
211224
212- // Enforce minimum refresh rate
213- if parsed .D4S .RefreshRate < 2.0 && parsed .D4S .RefreshRate > 0 {
214- parsed .D4S .RefreshRate = 2.0
225+ return loaded
226+ }
227+
228+ // LoadFile reads exactly configPath and returns an error if it cannot be read or parsed.
229+ func LoadFile (configPath string ) (* Config , error ) {
230+ if configPath == "" {
231+ return nil , errors .New ("config path is empty" )
232+ }
233+
234+ data , err := os .ReadFile (configPath )
235+ if err != nil {
236+ return nil , fmt .Errorf ("read config %q: %w" , configPath , err )
215237 }
216238
217- return parsed
239+ cfg , err := parse (data , configPath )
240+ if err != nil {
241+ return nil , err
242+ }
243+ cfg .sourcePath = configPath
244+ return cfg , nil
218245}
219246
220- // Save writes the config back to $XDG_CONFIG_HOME/d4s/config.yaml.
247+ // Save writes the config back to its explicit source file, or to the default
248+ // $XDG_CONFIG_HOME/d4s/config.yaml path when standard discovery was used.
221249func Save (cfg * Config ) error {
222250 if cfg == nil {
223251 return errors .New ("nil config" )
224252 }
225253
254+ configPath := cfg .sourcePath
255+ if configPath != "" {
256+ data , err := yaml .Marshal (cfg )
257+ if err != nil {
258+ return err
259+ }
260+ return os .WriteFile (configPath , data , 0o644 )
261+ }
262+
226263 dir := configDir ()
227264 if dir == "" {
228265 return errors .New ("unable to determine config directory" )
@@ -235,6 +272,6 @@ func Save(cfg *Config) error {
235272 return err
236273 }
237274
238- configPath : = filepath .Join (dir , "config.yaml" )
275+ configPath = filepath .Join (dir , "config.yaml" )
239276 return os .WriteFile (configPath , data , 0o644 )
240277}
0 commit comments