Neovim plugins: the folders

2024-01-02

This is a blog post in my series about what I wish I knew before I wrote my first Neovim plugin. If you have not already read part 1, check it out here.

One of the most difficult things for me to find information about for my first Neovim plugin, was how I would go from a function in init.lua, to a full-blown package which I could install from my plugin manager. In particular, it was difficult to understand the folder structure of the different packages I studied.

It turns out that the process is very similar to how you would do it for other programming languages when writing a package. There are only two directories required: ./lua/ and ./plugin/.

.
├── lua
│   ├── first-function.lua
│   ├── second-function.lua
│   ├── third-function.lua
│   └── fourth-function.lua
└── plugin
   └── package-name.lua

./lua/

The lua directory contains the lua functions of your package. You could put all the functions in a single file, but it is good practice to factor out functions into separate files, or at least group similar functions into a single file.

As an example, let’s say that the content of ./lua/hello.lua is:

function hello()
  local message = 'hello, world!'
  print(message)
end

I.e, it defines the lua function hello()

./plugin/

The plugin directory is what is loaded by the package manager. The main purpose of the files here is to source the required lua functions and define the user-facing functions. You can think of this as the “init.lua” of your package.

As an example, if we want to export the hello world function we defined in ./lua/hello.lua.

require('hello')

vim.api.nvim_create_user_command(
  'Hello',
  'lua hello()',
  {}
)

This will then export the lua function so that it can be called from the Neovim command mode as Hello.

Congratulations, you now have a minimal viable package which can be installed from your favorite Neovim package manager.