🔥 Developers
To make it easier for users to install your plugin, you can include a package spec in your repo.
Best Practices
-
If your plugin needs
setup(), then create a simplelazy.luafile like this:return { "me/my-plugin", opts = {} } -
Plugins that are pure lua libraries should be lazy-loaded with
lazy = true.{ "nvim-lua/plenary.nvim", lazy = true } -
Always use
optsinstead ofconfigwhen possible.configis almost never needed.GOOD{ "folke/todo-comments.nvim", opts = {} },BAD{
"folke/todo-comments.nvim",
config = function()
require("todo-comments").setup({})
end,
}, -
Only use
dependenciesif a plugin needs the dep to be installed AND loaded. Lua plugins/libraries are automatically loaded when they arerequire()d, so they don't need to be independencies.GOOD{ "folke/todo-comments.nvim", opts = {} },
{ "nvim-lua/plenary.nvim", lazy = true },BAD{
"folke/todo-comments.nvim",
opts = {},
-- This will always load plenary as soon as todo-comments loads,
-- even when todo-comments doesn't use it.
dependencies = { "nvim-lua/plenary.nvim", lazy = true },
}, -
Inside a
buildfunction or*.luabuild file, usecoroutine.yield(msg:string|LazyMsg)to show progress. -
Don't change the
cwdin your build function, since builds run in parallel and changing thecwdwill affect other builds.
Building
The spec build property can be one of the following:
fun(plugin: LazyPlugin): a function that builds the plugin.*.lua: a Lua file that builds the plugin (likebuild.lua)":Command": a Neovim command"rockspec": this will runluarocks makein the plugin's directory This is automatically set by therockspecpackage source.- any other string will be run as a shell command
- a
listof any of the above to run multiple build steps - if no
buildis specified, but abuild.luafile exists, that will be used instead.
Build functions and *.lua files run asynchronously in a coroutine.
Use coroutine.yield(msg:string|LazyMsg) to show progress.
Yielding will also schedule the next coroutine.resume() to run in the next tick, so you can do long-running tasks without blocking Neovim.
---@class LazyMsg
---@field msg string
---@field level? number vim.log.levels.XXX
Use vim.log.levels.TRACE to only show the message as a status message for the task.
If you need to know the directory of your build lua file, you can use:
local dir = vim.fn.fnamemodify(debug.getinfo(1, "S").source:sub(2), ":p:h")
Minit (Minimal Init)
lazy.nvim comes with some built-in functionality to help you create a minimal init for your plugin.
I mainly use this for testing and for users to create a repro.lua.
When running in headless mode, lazy.nvim will log any messages to the terminal.
See opts.headless for more info.
minit will install/load all your specs and will always run an update as well.
Bootstrap
-- setting this env will override all XDG paths
vim.env.LAZY_STDPATH = ".tests"
-- this will install lazy in your stdpath
load(vim.fn.system("curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua"))()
Testing with Busted
This will add "lunarmodules/busted", configure hererocks and run busted.
Below is an example of how I use minit to run tests with busted in LazyVim.
#!/usr/bin/env -S nvim -l
vim.env.LAZY_STDPATH = ".tests"
load(vim.fn.system("curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua"))()
-- Setup lazy.nvim
require("lazy.minit").busted({
spec = {
"LazyVim/starter",
"williamboman/mason-lspconfig.nvim",
"williamboman/mason.nvim",
"nvim-treesitter/nvim-treesitter",
},
})
To use this, you can run:
nvim -l ./tests/busted.lua tests
If you want to inspect the test environment, run:
nvim -u ./tests/busted.lua
repro.lua
vim.env.LAZY_STDPATH = ".repro"
load(vim.fn.system("curl -s https://raw.githubusercontent.com/folke/lazy.nvim/main/bootstrap.lua"))()
require("lazy.minit").repro({
spec = {
"stevearc/conform.nvim",
"nvim-neotest/nvim-nio",
},
})
-- do anything else you need to do to reproduce the issue
Then run it with:
nvim -u repro.lua