--- title: So you want to write a neovim plugin with lua date: 2024-04-06 tags: - lua - neovim draft: false --- I've recently been messing around with writing neovim plugins. When I initially got going I found it a little tricky to know how to get started. There's the [official neovim docs](https://neovim.io/doc) which are great; but in my beginner experience exhaustive to the point of slight impenetrability. Beyond that, the thing I found most useful was simply reading the source of some popular plugins to get an idea of how things worked. I would recommend sticking to plugins with a smaller scope though. As a demostrative MVP (minimal viable plugin) jumping-off-point, I'm going to make a very simple note-taking plugin. It will provide a command to neovim which when run opens a file titled with the date and time in a specific notes directory. Vamos. This is what you will want your directory structure to look like. ```bash ├── lua │ └── note │ └── init.lua └── plugin └── note.vim ``` The `plugin/note.vim` file will look like this. ```vim command! Note lua require("note").main() ``` This creates a custom command `Note` which when run will call a lua function. Now on to where that function and the meat of the plugin logic will live: the `lua/note/init.lua` file. With more complex plugins this section will often be split into many files but we've just got one here as it's so simple. First things first we create a plugin object. ```lua local note = {} ``` Then we will define some default options for the plugin in a table. These are variables you want the user to be able to change when they call the setup function. ```lua local defaults = { note_directory = "~/notes/", date_format = "%Y-%m-%d %H:%M", file_extension = ".md", } ``` Next we need the setup function. This takes the user's options and merges them with our default options. ```lua function note.setup(user_options) options = vim.tbl_deep_extend("force", defaults, user_options or {}) end ``` This is the main function where the magic happens. ```lua function note.main() local dir = options.note_directory local name = os.date(options.date_format) local ext = options.file_extension local filename = string.format("%s%s%s", dir, name, ext) local command = string.format("edit %s", filename) vim.api.nvim_command(command) end ``` Finally we return the plugin obect. ```lua return note ``` At this point you should have a working plugin :) As a little coda, this is how you can use your fancy new plugin using [lazy.nvim](https://github.com/folke/lazy.nvim/). ```lua require("lazy").setup({ { -- local dir = "~/neovim-note-plugin", -- github -- "me/neovim-note-plugin", -- alternative non github hosting -- url = "https://git.example.com/me/neovim note-plugin", config = fucntion() require("note").setup({ file_extension = ".org", }) end, } }) ``` Hope you've enjoyed.