1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
2//
3// SPDX-License-Identifier: AGPL-3.0-or-later
4
5package config
6
7import (
8 "errors"
9 "fmt"
10 "io/fs"
11 "os"
12 "path/filepath"
13 "strings"
14
15 "git.secluded.site/np/internal/db"
16 "git.secluded.site/np/internal/i18n"
17 "github.com/BurntSushi/toml"
18)
19
20const (
21 configFileName = "config.toml"
22)
23
24// Config captures user configuration for the CLI.
25type Config struct {
26 UI UIConfig `toml:"ui"`
27}
28
29// UIConfig configures user-facing behaviour.
30type UIConfig struct {
31 Language string `toml:"language"`
32}
33
34// Path resolves the configuration file location.
35func Path() (string, error) {
36 dbPath, err := db.DefaultPath()
37 if err != nil {
38 return "", err
39 }
40 return filepath.Join(filepath.Dir(dbPath), configFileName), nil
41}
42
43// Load attempts to read configuration from disk. Missing files fall back to
44// defaults without error.
45func Load() (Config, error) {
46 cfg := Config{
47 UI: UIConfig{
48 Language: i18n.DefaultLanguage,
49 },
50 }
51
52 path, err := Path()
53 if err != nil {
54 return cfg, err
55 }
56
57 data, err := os.ReadFile(path)
58 if err != nil {
59 if errors.Is(err, fs.ErrNotExist) {
60 return cfg, nil
61 }
62 return cfg, fmt.Errorf("config: read %q: %w", path, err)
63 }
64
65 if err := toml.Unmarshal(data, &cfg); err != nil {
66 return cfg, fmt.Errorf("config: parse %q: %w", path, err)
67 }
68
69 cfg.UI.Language = normaliseLanguage(cfg.UI.Language)
70 return cfg, nil
71}
72
73func normaliseLanguage(lang string) string {
74 lang = strings.TrimSpace(strings.ToLower(lang))
75 if lang == "" {
76 return i18n.DefaultLanguage
77 }
78 return lang
79}