▍ humdrum codex / glint v1.0.2
license AGPL-3.0
3.3 KB raw
  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")
}