I like minpac, it's a good plugin manager. It does what I want. Exactly what I want. Problem is it's written in vimscript, which is something I'm trying to avoid right now. I have no good reason to avoid vimscript... I just don't want to write any. By now I have read enough about lua and the neovim api to create a wrapper that would make minpac
a little bit more "lua friendly".
Let me show you what we are running away from.
In the before times...
If you browse in the README file of minpac
you'll notice this example code.
function! PackInit() abort
packadd minpac
call minpac#init()
call minpac#add('k-takata/minpac', {'type': 'opt'})
" Additional plugins here.
call minpac#add('vim-jp/syntax-vim-ex')
call minpac#add('tyru/open-browser.vim')
endfunction
" Define user commands for updating/cleaning the plugins.
" Each of them calls PackInit() to load minpac and register
" the information of plugins, then performs the task.
command! PackUpdate call PackInit() | call minpac#update()
command! PackClean call PackInit() | call minpac#clean()
command! PackStatus packadd minpac | call minpac#status()
We got this global function which does two things, it initializes minpac and registers the plugins. Then create we commands that actually use this function and call the action we want.
What I like about this is nothing gets executed until is needed. minpac
really does get out of your way once your plugins are ready. Now, I want this in lua.
First try
What if we want to translate that snippet? How would it look like in lua? Here is the answer.
function PackInit()
vim.cmd('packadd minpac')
vim.call('minpac#init')
local add = vim.fn['minpac#add']
-- Additional plugins here.
add('k-takata/minpac', {type = 'opt'})
add('vim-jp/syntax-vim-ex')
add('tyru/open-browser.vim')
end
-- Define user commands for updating/cleaning the plugins.
-- Each of them calls PackInit() to load minpac and register
-- the information of plugins, then performs the task.
vim.cmd [[
command! PackUpdate lua PackInit(); vim.call('minpac#update')
command! PackClean lua PackInit(); vim.call('minpac#clean')
command! PackStatus lua PackInit(); vim.call('minpac#status')
]]
I don't hate this but I know we can do better. But what? What can we do? Hide things behind a pretty interface.
Modules to the rescue
Basically, what we will do is create a module that hides all the ugly things we don't want in the regular config.
local M = {}
-- Register the plugins
M.add = function(name, opts)
opts = opts or vim.empty_dict()
-- "do" is a keyword in lua.
-- We make a "run" alias to save ourselves some troubles
opts['do'] = opts.run
opts.run = nil
vim.call('minpac#add', name, opts)
end
-- The setup
M.init = function(opts)
opts = opts or vim.empty_dict()
vim.cmd('packadd minpac')
vim.call('minpac#init', opts)
end
-- The heavy lifting happens here
M.run = function(action, arg)
-- Higher order functions FTW!
M.use(M.add)
vim.call(action, arg)
end
M.setup_commands = function()
vim.cmd [[
command! PackUpdate lua require('usermod.minpac').run('minpac#update', '')
command! PackStatus lua require('usermod.minpac').run('minpac#status')
command! PackClean lua require('usermod.minpac').run('minpac#clean')
]]
end
-- Just know that if you use `require` this will only be executed once.
-- Regardless, nothing bad will happens if you run this again.
M.setup_commands()
return M
For the sake of this example let's say we have that module in this path: ~/.config/nvim/lua/usermod/minpac.lua
. And we use it like this.
local minpac = require('usermod.minpac')
minpac.use = function(add)
minpac.init()
-- Additional plugins here.
add('k-takata/minpac', {type = 'opt'})
add('vim-jp/syntax-vim-ex')
add('tyru/open-browser.vim')
-- This a cool theme
add('VonHeikemen/rubber-themes.vim', {
type = 'opt',
run = function()
vim.opt.termguicolors = true
vim.cmd('colorscheme rubber')
end
})
end
The best part is, since we are taking add
as an argument we can call it whatever we want. The following is also valid.
local minpac = require('usermod.minpac')
minpac.use = function(Plug)
minpac.init()
-- Additional plugins here.
Plug('k-takata/minpac', {type = 'opt'})
-- If you only need the first argument
-- you can omit the parenthesis
Plug 'vim-jp/syntax-vim-ex'
Plug 'tyru/open-browser.vim'
-- rest of the plugins...
end
Thanks to the way lua works we can get a vim-plug-ish syntax for free.
To be fair we could also do that in the "first try" section.
local Plug = vim.fn['minpac#add']
That would be enough.
Conclusion
We figure out we could use minpac
directly in lua using just the neovim api, nothing special at first. Then we decided that wasn't enough, and we used lua modules to create a nice api that would great on fancy screenshots. Lastly, we discoreved some lua sourcery that allows us to write a syntax that is closed to the used by vim-plug.
Sources
Thank you for your time. If you find this article useful and want to support my efforts, consider leaving a tip in ko-fi.com/vonheikemen.
Top comments (0)