nvim/lua/core/config.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