-- This is the runtime for my custom nix-based neovim configuration system local M = {} local H = {} M.helpers = H -- {{{ General helpers function H.with_default(default, given) if given == nil then return default else return given end end -- {{{ Strings function H.string_chars(str) local chars = {} for i = 1, #str do table.insert(chars, str:sub(i, i)) end return chars end function H.split(text, sep) ---@diagnostic disable-next-line: redefined-local local sep, fields = sep or ":", {} local pattern = string.format("([^%s]+)", sep) text:gsub(pattern, function(c) fields[#fields + 1] = c end) return fields end -- }}} -- {{{ Tables function H.mergeTables(t1, t2) local t3 = {} if t1 ~= nil then for k, v in pairs(t1) do t3[k] = v end end if t2 ~= nil then for k, v in pairs(t2) do t3[k] = v end end return t3 end -- }}} -- }}} -- {{{ API wrappers -- {{{ Keymaps function M.set_keymap(opts, context) if context == nil then context = {} end local buffer = nil if context.bufnr ~= nil then buffer = context.bufnr end local action = opts.action if type(opts.action) == "function" then action = function() opts.action(context) end end vim.keymap.set( H.string_chars(H.with_default("n", opts.mode)), opts.mapping, action, { desc = opts.desc, buffer = H.with_default(buffer, opts.buffer), expr = opts.expr, silent = H.with_default(true, opts.silent), } ) end -- }}} -- {{{ Autocmds function M.create_autocmd(opts) local callback if type(opts.action) == "function" then callback = opts.action end if type(opts.action) == "table" then callback = function(event) M.configure(opts.action, event) end end vim.api.nvim_create_autocmd(opts.event, { group = vim.api.nvim_create_augroup(opts.group, {}), pattern = H.with_default("*", opts.pattern), callback = callback, }) end -- }}} -- }}} -- {{{ Main config runtime local function recursive_assign(source, destination) for key, value in pairs(source) do if type(value) == "table" and type(destination[key]) == "table" then recursive_assign(value, destination[key]) else destination[key] = value end end end function M.configure(opts, context) -- {{{ Construct opts & context if type(opts) == "function" then opts = opts(context) end if type(opts) ~= "table" then -- TODO: throw return end if type(opts.mkContext) == "function" then context = opts.mkContext(context) end -- }}} if opts.cond == false or type(opts.cond) == "function" and opts.cond(context) == false then return end if type(opts.vim) == "table" then recursive_assign(opts.vim, vim) end -- {{{ Keybinds if type(opts.keys) == "function" then opts.keys = opts.keys(context) end if type(opts.keys) == "table" then local keys = opts.keys -- Detect single key passed instead of array if keys.mapping ~= nil then keys = { keys } end for _, keymap in ipairs(keys) do M.set_keymap(keymap, context) end end -- }}} -- {{{ Autocmds if type(opts.autocmds) == "function" then opts.autocmds = opts.autocmds(context) end if type(opts.autocmds) == "table" then local autocmds = opts.autocmds -- Detect single autocmd passed instead of array if autocmds.event ~= nil then autocmds = { autocmds } end for _, autocmd in ipairs(autocmds) do M.create_autocmd(autocmd) end end -- }}} -- {{{ .setup calls if type(opts.setup) == "table" then for key, arg in pairs(opts.setup) do require(key).setup(arg) end end if type(context) == "table" and context.lazy ~= nil and context.opts ~= nil and vim.inspect(context.opts) ~= "{}" then -- This is a terrible way to do it :/ local status, module = pcall(require, context.lazy.name) if status then module.setup(context.opts) end end -- }}} -- {{{ Callbacks if type(opts.callback) == "function" then opts.callback(context) end if type(opts.callback) == "table" then M.configure(opts.callback, context) end -- }}} end function M.configureMany(specs, context) for _, spec in ipairs(specs) do M.configure(spec, context) end end -- }}} -- {{{ Neovim env handling local envs = { vscode = vim.g.vscode ~= nil, neovide = vim.g.neovide ~= nil or vim.g.nix_neovim_app == "neovide", firenvim = vim.g.started_by_firenvim ~= nil or vim.g.nix_neovim_app == "firenvim", } M.blacklist = function(list) if type(list) == "string" then list = { list } end for _, key in pairs(list) do if envs[key] then return false end end return true end M.whitelist = function(list) if type(list) == "string" then list = { list } end for _, key in pairs(list) do if not envs[key] then return false end end return true end -- }}} -- {{{ Other misc thingies function M.withSavedCursor(callback) local cursor = vim.api.nvim_win_get_cursor(0) callback() vim.api.nvim_win_set_cursor(0, cursor) end -- }}} -- {{{ Fixup lazy spec generated by nix function M.prepareLazySpec(spec) for _, module in ipairs(spec) do if module.package ~= nil then module[1] = module.package module.package = nil end local configType = type(module.config) if configType == "function" or configType == "table" then local previousConfig = module.config module.config = function(lazy, opts) M.configure(previousConfig, { lazy = lazy, opts = opts }) end end local initType = type(module.init) if initType == "function" or initType == "table" then local previousInit = module.init module.init = function(lazy, opts) M.configure(previousInit, { lazy = lazy, opts = opts }) end end if module.keys ~= nil then if type(module.keys) == "string" or module.keys.mapping ~= nil then module.keys = { module.keys } end for _, key in ipairs(module.keys) do if type(key) ~= "string" then key[1] = key.mapping key.mapping = nil if key.mode ~= nil then key.mode = H.string_chars(key.mode) end if key.action ~= nil then key[2] = key.action key.action = nil end end end end if type(module.cond) == "table" then local final = true for _, cond in ipairs(module.cond) do final = final and cond end module.cond = final end end end -- }}} -- {{{ Theming local theme = vim.g.nix_theme M.theme = theme function M.theme_contains(name) return string.find(theme.name, name) ~= nil end function M.theme_variant(name) -- +1 for 1-indexed strings and +1 for the space between name and variant return string.lower(string.sub(theme.name, string.len(name) + 2)) end -- }}} return M