Modularity is something I’ve always considered top priority when it comes to my configs; being able to split things up into smaller pieces and have them spatially separated helps me understand/work with them. For this reason, I found typical Packer usage a little annoying, as you can only have one call to packer.start, and so regardless of where you put your configs, you are more or less forced to have every plugin specified in that call.
So, what to do about that?
Well, as a Nix/Home-Manager user, I’ve grown to very much appreciate HM’s module system and ‘passive’ (for lack of a better term) merging/overlaying of configs, and I got to thinking how I could possibly replicate that behavior in some way within my Neovim conf.
My approach
Define a layout for a “Module”.
A valid module file is a .lua
file that returns a table with the following keys:
- SETUP: A typical standalone lambda that should be run for setup/use of the module before packages are installed
- PACKAGES: A suite of packages to be installed by packer
- CONFIG: A typical standalone lambda that should be run after packages are installed
- EXPORTS: A table of functions/values to be exported
- RUN: Arbitrary lua code to be run at any time when invoked
- If any of the keys are not found they should be appropriately interpreted as being empty
Activation flow:
- ~merge module fields~
- run all setups
- merge packages into one table and then call
use
on all of them in apacker.setup
call - run all configs
- exports should be available to global access under their respective module names
The code required to make this happen is actually very small, I have some cruft and currently unused and unfinished functions, but the I’d estimate working LoC’s at below 50. See the activate_all
function here: nixrc/module.lua at master · samuelludwig/nixrc · GitHub
I invoke my modules in my init.lua
like so:
local f = require('lib.fun')
local mod = require('lib.module')
require('packer-bootstrap')
local prepend_mod_dot = function(x)
return 'modules.' .. x
end
local mod_list = f.totable(f.map(prepend_mod_dot, {
'core',
'telescope-mod',
'language_smartness',
'vimwiki-mod',
'lualine',
'themes',
'interface-helpers',
'file-tree',
'terminal',
}))
mod.activate_all(mod_list)
I have some cleaning up to do with my existing modules (and i still have normal configs mixed in that I need to move elsewhere), but you can see what I’m currently working with here: nixrc/modules/user/nvim/lua/dot/modules at master · samuelludwig/nixrc · GitHub
What I’d still like to do
I’ve been trying to think of a way to have a module “require” another, which would have it be implicitly added into the modules list before the requiring module is evaluated.