1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
// Package config loads glint's TOML configuration, falling back to defaults.
package config
import (
"errors"
"fmt"
"os"
"path/filepath"
"time"
"github.com/BurntSushi/toml"
)
// Config holds the user-tunable settings glint reads at startup.
type Config struct {
VaultDir string `toml:"vault_dir"` // the vault `glint vault` opens from anywhere
DailySubdir string `toml:"daily_subdir"`
DailyFormat string `toml:"daily_format"`
GlamourStyle string `toml:"glamour_style"`
Theme string `toml:"theme"`
InboxDir string `toml:"inbox_dir"`
}
// Default returns the built-in configuration used when no file is present.
// VaultDir is empty by default: bare glint works in the current directory; set
// vault_dir (config) to give `glint vault` a fixed vault to open from anywhere.
func Default() Config {
return Config{
DailySubdir: "Daily",
DailyFormat: "2006-01-02",
Theme: "auto",
}
}
// WorkingDir is where bare `glint`, `glint new`, and `--daily` operate: the
// $GLINT_VAULT pin if set, otherwise the current working directory.
func (c Config) WorkingDir() string {
if v := os.Getenv("GLINT_VAULT"); v != "" {
return v
}
if wd, err := os.Getwd(); err == nil {
return wd
}
return "."
}
// Vault is the directory `glint vault` opens from anywhere: the configured
// vault_dir, or the working directory when none is set.
func (c Config) Vault() string {
if c.VaultDir != "" {
return c.VaultDir
}
return c.WorkingDir()
}
// Load reads ~/.config/glint/config.toml and overlays it onto the defaults.
func Load() (Config, error) {
home, err := os.UserHomeDir()
if err != nil {
return Default(), nil
}
return loadFromFile(filepath.Join(home, ".config", "glint", "config.toml"))
}
// loadFromFile is the testable core of Load. A missing file yields the
// defaults with no error; a malformed file yields the defaults plus an error.
func loadFromFile(path string) (Config, error) {
cfg := Default()
data, err := os.ReadFile(path)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
return cfg, nil // absent config is fine
}
return cfg, fmt.Errorf("read %s: %w", path, err)
}
var fileCfg Config
if _, err := toml.Decode(string(data), &fileCfg); err != nil {
return cfg, fmt.Errorf("parse %s: %w", path, err)
}
if fileCfg.VaultDir != "" {
cfg.VaultDir = fileCfg.VaultDir
}
if fileCfg.DailySubdir != "" {
cfg.DailySubdir = fileCfg.DailySubdir
}
if fileCfg.DailyFormat != "" {
cfg.DailyFormat = fileCfg.DailyFormat
}
if fileCfg.GlamourStyle != "" {
cfg.GlamourStyle = fileCfg.GlamourStyle
}
if fileCfg.Theme != "" {
cfg.Theme = fileCfg.Theme
}
if fileCfg.InboxDir != "" {
cfg.InboxDir = fileCfg.InboxDir
}
return cfg, nil
}
// InboxRoot is the directory new notes default into: the working directory when
// InboxDir is empty, an absolute InboxDir as-is, or InboxDir resolved under the
// working directory when relative.
func (c Config) InboxRoot() string {
if c.InboxDir == "" {
return c.WorkingDir()
}
if filepath.IsAbs(c.InboxDir) {
return c.InboxDir
}
return filepath.Join(c.WorkingDir(), c.InboxDir)
}
// DailyPath builds the path to the daily note for time t, under the working dir.
func (c Config) DailyPath(t time.Time) string {
return filepath.Join(c.WorkingDir(), c.DailySubdir, t.Format(c.DailyFormat)+".md")
}
|