2023-05-20: Updated to account for the features of NeoVim 0.9 and obsolete plugins

You have found a (Neo)Vim plugin that you want to fiddle with, either to contribute changes upstream or for your own use. Sounds familiar? Here are some tips and tricks I use for my NeoVim plugin development. The aim of these small tricks is to iterate faster on changes, by loading your changes in a live NeoVim instance as quickly as possible.

We will use telescope-repo.nvim as an example but it is applicable to any plugin (although some sections of this post only apply to Lua NeoVim plugins).

Load Local Plugin Version

When developing, you make your changes to a local git repository, for instance ~/ghq/github.com/cljoly/telescope-repo.nvim. To test those changes, you need to tell NeoVim to load the plugin from the local repository, instead of using the location set by your plugin manager. To do this, just append the following near the beginning of your init.lua file:

vim.opt.runtimepath:prepend("~/ghq/github.com/cljoly/telescope-repo.nvim")

Note the :prepend. It will ensure that your local dev version will override anything installed by your nvim package manager. This way no need to uninstall your plugin when developing!

Reloading Changes in a Live NeoVim Instance

You have now made some changes to the plugin that you would like to test. In doing so, you start a second NeoVim instance and open a set of files, change a bunch of settings…

You then change something in the code, but you don’t want to restart you test NeoVim instance, as that would mean reopening files and altering settings all over again. But just doing require(…) is not enough, because require caches already loaded files and doesn’t reload them if they are loaded already.

If you use telescope, you can use the reloader picker. You can then select the module you want to reload, like so:

You type “telescop repo” and the corresponding Lua module surfaces. It will be reloaded when you hit Enter.
Telescope reloader in action

You type “telescop repo” and the corresponding Lua module surfaces. It will be reloaded when you hit Enter.

Under the hood, telescope reload uses plenary:

require("plenary.reload").reload_module(selection.value)

which handle various cases (like whether impatient.nvim is used at the time of writing). Despite this careful handling, sometimes, a plugin may not fully reload. In that case, you want to automate as much of the setup as possible on NeoVim restart.

If All Else Fails

Sometimes, a “soft” reloading is not enough and you need to restart NeoVim. For instance, if we are testing the :Telescope repo list command and need to open /tmp/file, we can do:

nvim +'Telescope repo list' /tmp/file

and even place this in an infinite loop with a sleep command, to escape the loop more easily once we are done.

Of course, you will want to replace Telescope repo list with the command you want to test. You can also add more setup by supplying multiple “+'…'” arguments)

All Set

Now that you are all set, you can go on and write complete plugins! You may find the following resources useful in your journey:

  • the :help lua-guide.txt has a lot of resources to write plugins and alter NeoVim’s configuration,
    • 2n.pl walks through writing a simple plugin,
  • set up a Language Server Protocol for Lua,
    • and maybe even a full-blown plugin for Lua plugin development,
  • to test a piece of Lua code real quick, :=my.lua.code(here) is great. For bigger pieces of code, luapad can be useful: it provides a scratch buffer where the result of a Lua snippet is displayed as you type.