157 lines
3.8 KiB
Lua
157 lines
3.8 KiB
Lua
-- Config loader module
|
|
-- Loads user configuration from config.json with defaults and validation
|
|
|
|
local M = {}
|
|
|
|
-- Default configuration values
|
|
M.defaults = {
|
|
paths = {
|
|
obsidianVault = "~/Documents/obsidian-vault/",
|
|
srcDirectory = "~/.local/src/",
|
|
scriptsDirectory = "~/scripts/",
|
|
wallpaperScript = "~/scripts/pywal/wallpapermenu.sh",
|
|
},
|
|
editor = {
|
|
tabSize = 4,
|
|
scrollOffset = 8,
|
|
theme = "wave",
|
|
},
|
|
ai = {
|
|
model = "claude-sonnet-4-5",
|
|
openCodeModel = "anthropic/claude-sonnet-4-5",
|
|
},
|
|
lsp = {
|
|
servers = { "ts_ls", "eslint", "jsonls", "html", "cssls", "tailwindcss" },
|
|
},
|
|
treesitter = {
|
|
languages = { "lua", "vim", "bash", "javascript", "typescript", "tsx", "json", "yaml", "html", "css" },
|
|
},
|
|
}
|
|
|
|
-- Cache for loaded config
|
|
local config_cache = nil
|
|
|
|
-- Deep merge two tables (b overrides a)
|
|
local function deep_merge(a, b)
|
|
local result = vim.deepcopy(a)
|
|
for k, v in pairs(b) do
|
|
if type(v) == "table" and type(result[k]) == "table" then
|
|
result[k] = deep_merge(result[k], v)
|
|
else
|
|
result[k] = v
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
-- Expand ~ to home directory in paths
|
|
local function expand_path(path)
|
|
if type(path) ~= "string" then
|
|
return path
|
|
end
|
|
return path:gsub("^~", vim.fn.expand("$HOME"))
|
|
end
|
|
|
|
-- Recursively expand paths in a table
|
|
local function expand_paths(tbl)
|
|
-- Check if this is an array (sequential numeric keys)
|
|
if #tbl > 0 then
|
|
local result = {}
|
|
for i, v in ipairs(tbl) do
|
|
result[i] = v
|
|
end
|
|
return result
|
|
end
|
|
|
|
local result = {}
|
|
for k, v in pairs(tbl) do
|
|
if type(v) == "table" then
|
|
result[k] = expand_paths(v)
|
|
elseif type(v) == "string" and type(k) == "string" and (k:lower():match("path") or k:lower():match("vault") or k:lower():match("directory") or k:lower():match("script")) then
|
|
result[k] = expand_path(v)
|
|
else
|
|
result[k] = v
|
|
end
|
|
end
|
|
return result
|
|
end
|
|
|
|
-- Load configuration from config.json
|
|
function M.load()
|
|
if config_cache then
|
|
return config_cache
|
|
end
|
|
|
|
local config_path = vim.fn.stdpath("config") .. "/config.json"
|
|
local user_config = {}
|
|
|
|
-- Check if config file exists
|
|
if vim.fn.filereadable(config_path) == 1 then
|
|
local file = io.open(config_path, "r")
|
|
if file then
|
|
local content = file:read("*a")
|
|
file:close()
|
|
|
|
-- Try to parse JSON
|
|
local ok, parsed = pcall(vim.json.decode, content)
|
|
if ok and type(parsed) == "table" then
|
|
user_config = parsed
|
|
else
|
|
vim.notify("config.json: Parse error, using defaults", vim.log.levels.WARN)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Merge defaults with user config
|
|
local merged = deep_merge(M.defaults, user_config)
|
|
|
|
-- Expand paths
|
|
config_cache = expand_paths(merged)
|
|
|
|
return config_cache
|
|
end
|
|
|
|
-- Get a config value by dot-notation path (e.g., "paths.obsidianVault")
|
|
function M.get(path)
|
|
local config = M.load()
|
|
local keys = vim.split(path, ".", { plain = true })
|
|
local value = config
|
|
|
|
for _, key in ipairs(keys) do
|
|
if type(value) ~= "table" then
|
|
return nil
|
|
end
|
|
value = value[key]
|
|
end
|
|
|
|
return value
|
|
end
|
|
|
|
-- Convenience getters for common sections
|
|
function M.paths()
|
|
return M.load().paths
|
|
end
|
|
|
|
function M.editor()
|
|
return M.load().editor
|
|
end
|
|
|
|
function M.ai()
|
|
return M.load().ai
|
|
end
|
|
|
|
function M.lsp()
|
|
return M.load().lsp
|
|
end
|
|
|
|
function M.treesitter()
|
|
return M.load().treesitter
|
|
end
|
|
|
|
-- Reset cache (useful for testing or config reload)
|
|
function M.reset()
|
|
config_cache = nil
|
|
end
|
|
|
|
return M
|