Files
gems/opal-task/internal/engine/config.go
T
joakim 43bbefbc00 Phase 2: Add config support for week_start_day and default_due_time
- Add WeekStartDay and DefaultDueTime fields to Config struct
- Set defaults: week_start_day=monday, default_due_time=empty
- Add GetWeekStart() and GetDefaultDueTime() helper methods
- Update ParseDate() to use configured week start day
- All tests passing
2026-01-05 09:55:33 +01:00

145 lines
3.5 KiB
Go

package engine
import (
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/spf13/viper"
)
type Config struct {
DefaultFilter string `mapstructure:"default_filter"`
DefaultSort string `mapstructure:"default_sort"`
ColorOutput bool `mapstructure:"color_output"`
WeekStartDay string `mapstructure:"week_start_day"`
DefaultDueTime string `mapstructure:"default_due_time"`
}
var globalConfig *Config
// GetConfigDir returns the configuration directory path
func GetConfigDir() (string, error) {
home, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("failed to get home directory: %w", err)
}
return filepath.Join(home, ".config", "jade"), nil
}
// GetDBPath returns the path to the SQLite database
func GetDBPath() (string, error) {
configDir, err := GetConfigDir()
if err != nil {
return "", err
}
return filepath.Join(configDir, "opal.db"), nil
}
// GetConfigPath returns the path to the config file
func GetConfigPath() (string, error) {
configDir, err := GetConfigDir()
if err != nil {
return "", err
}
return filepath.Join(configDir, "opal.yml"), nil
}
// LoadConfig loads the configuration from file or creates default
func LoadConfig() (*Config, error) {
if globalConfig != nil {
return globalConfig, nil
}
configDir, err := GetConfigDir()
if err != nil {
return nil, err
}
// Ensure config directory exists
if err := os.MkdirAll(configDir, 0755); err != nil {
return nil, fmt.Errorf("failed to create config directory: %w", err)
}
configPath, err := GetConfigPath()
if err != nil {
return nil, err
}
v := viper.New()
v.SetConfigFile(configPath)
v.SetConfigType("yaml")
// Set defaults
v.SetDefault("default_filter", "status:pending")
v.SetDefault("default_sort", "due,priority")
v.SetDefault("color_output", true)
v.SetDefault("week_start_day", "monday")
v.SetDefault("default_due_time", "")
// Try to read existing config
err = v.ReadInConfig()
if err != nil {
// Config doesn't exist, create it with defaults
// Write config with defaults (ignoring the error type check for now)
if err := v.WriteConfigAs(configPath); err != nil {
return nil, fmt.Errorf("failed to create config file: %w", err)
}
// Try reading again
if err := v.ReadInConfig(); err != nil {
return nil, fmt.Errorf("failed to read newly created config: %w", err)
}
}
cfg := &Config{}
if err := v.Unmarshal(cfg); err != nil {
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
}
globalConfig = cfg
return cfg, nil
}
// SaveConfig saves the configuration to file
func SaveConfig(cfg *Config) error {
configPath, err := GetConfigPath()
if err != nil {
return err
}
v := viper.New()
v.SetConfigFile(configPath)
v.SetConfigType("yaml")
v.Set("default_filter", cfg.DefaultFilter)
v.Set("default_sort", cfg.DefaultSort)
v.Set("color_output", cfg.ColorOutput)
v.Set("week_start_day", cfg.WeekStartDay)
v.Set("default_due_time", cfg.DefaultDueTime)
return v.WriteConfig()
}
// GetConfig returns the loaded config or loads it if not already loaded
func GetConfig() (*Config, error) {
if globalConfig != nil {
return globalConfig, nil
}
return LoadConfig()
}
// GetWeekStart returns the configured week start day
func (c *Config) GetWeekStart() time.Weekday {
if strings.ToLower(c.WeekStartDay) == "sunday" {
return time.Sunday
}
return time.Monday // default
}
// GetDefaultDueTime returns the configured default due time (HH:MM format or empty)
func (c *Config) GetDefaultDueTime() string {
return c.DefaultDueTime
}