22
33 NVIM REFERENCE MANUAL
44
5- Guide to developing Lua plugins for Nvim
5+ Guide to developing Lua plugins for Nvim
66
77
88 Type | gO | to see the table of contents.
99
1010==============================================================================
1111Introduction *lua-plugin*
1212
13- This is a guide for getting started with Nvim plugin development. It is not
14- intended as a set of rules, but as a collection of recommendations for good
15- practices.
13+ This document provides guidance for developing Nvim (Lua) plugins:
1614
17- For a guide to using Lua in Nvim, please refer to | lua-guide | .
15+ See | lua-guide | for guidance on using Lua to configure and operate Nvim.
16+ See | luaref | and | lua-concepts | for details on the Lua programming language.
17+
18+ ==============================================================================
19+ Creating your first plugin *lua-plugin-new*
20+
21+ Any Vimscript or Lua code file that lives in the right directory,
22+ automatically is a "plugin". There's no maniest or "registration" required.
23+
24+ You can try it right now:
25+
26+ 1. Visit your config directory: >
27+ :exe 'edit' stdpath('config')
28+ <
29+ 2. Create a `plugin /foo.lua ` file in there.
30+ 3. Add something to it, like: >lua
31+ vim.print('Hello World')
32+ <
33+ 4. Start `nvim` and notice that it prints "Hello World" in the messages area.
34+ Check `:messages ` if you don't see it.
35+
36+ Besides `plugin /foo.lua ` , which is always run at startup, you can define Lua
37+ modules in the `lua /` directory. Those modules aren't loaded until your
38+ `plugin /foo.lua ` , the user, calls `require (…)` .
1839
1940==============================================================================
2041Type safety *lua-plugin-type-safety*
@@ -24,24 +45,24 @@ virtually immediate feedback.
2445But for larger projects, this can be a double-edged sword, leaving your plugin
2546susceptible to unexpected bugs at the wrong time.
2647
27- You can leverage LuaCATS https://luals.github.io/wiki/annotations/
28- annotations, along with lua-language-server https://luals.github.io/ to catch
29- potential bugs in your CI before your plugin's users do.
48+ You can leverage LuaCATS or "emmylua" annotations https://luals.github.io/wiki/annotations/
49+ along with lua-language-server ("LuaLS") https://luals.github.io/ to catch
50+ potential bugs in your CI before your plugin's users do. The Nvim codebase
51+ uses these annotations extensively.
3052
31- ------------------------------------------------------------------------------
32- Tools *lua-plugin-type-safety-tools*
53+ TOOLS
3354
3455- lua-typecheck-action https://github.com/marketplace/actions/lua-typecheck-action
3556- lua-language-server https://luals.github.io
3657
3758==============================================================================
38- Keymaps *lua-plugin-keymaps*
59+ Keymaps *lua-plugin-keymaps*
3960
40- Avoid creating keymaps automatically, unless they are not controversial. Doing
41- so can easily lead to conflicts with user | mapping | s.
61+ Avoid creating excessive keymaps automatically. Doing so can conflict with
62+ user | mapping | s.
4263
4364NOTE: An example for uncontroversial keymaps are buffer-local | mapping | s for
44- specific file types or floating windows.
65+ specific file types or floating windows, or <Plug> mappings .
4566
4667A common approach to allow keymap configuration is to define a declarative DSL
4768https://en.wikipedia.org/wiki/Domain-specific_language via a `setup` function.
@@ -81,25 +102,24 @@ Some benefits of exposing a Lua function are:
81102NOTE: If your function takes an options table, users may still benefit
82103 from | <Plug> | mappings for the most common combinations.
83104
84- ------------------------------------------------------------------------------
85- Example *lua-plugin-plug-mapping-example*
105+ KEYMAP EXAMPLE
86106
87107In your plugin:
88108>lua
89- vim.keymap.set("n", " <Plug> (SayHello)" , function()
90- print(" Hello from normal mode" )
109+ vim.keymap.set('n', ' <Plug> (SayHello)' , function()
110+ print(' Hello from normal mode' )
91111 end, { noremap = true })
92112
93- vim.keymap.set("v", " <Plug> (SayHello)" , function()
94- print(" Hello from visual mode" )
113+ vim.keymap.set('v', ' <Plug> (SayHello)' , function()
114+ print(' Hello from visual mode' )
95115 end, { noremap = true })
96116<
97117In the user's config:
98118>lua
99- vim.keymap.set({"n", "v" }, " <leader> h", " <Plug> (SayHello)" )
119+ vim.keymap.set({'n', 'v' }, ' <leader> h', ' <Plug> (SayHello)' )
100120<
101121==============================================================================
102- Initialization *lua-plugin-initialization *
122+ Initialization *lua-plugin-init *
103123
104124Newcomers to Lua plugin development will often put all initialization logic in
105125a single `setup` function, which takes a table of options.
@@ -109,8 +129,8 @@ your plugin, even if they are happy with the default configuration.
109129Strictly separated configuration and smart initialization allow your plugin to
110130work out of the box.
111131
112- NOTE: A well designed plugin has minimal impact on startup time.
113- See also | lua-plugin-lazy-loading | .
132+ NOTE: A well designed plugin has minimal impact on startup time. See also
133+ | lua-plugin-lazy | .
114134
115135Common approaches to a strictly separated configuration are:
116136
@@ -124,37 +144,45 @@ Typically, automatic initialization logic is done in a |plugin| or |ftplugin|
124144script. See also | 'runtimepath' | .
125145
126146==============================================================================
127- Lazy loading *lua-plugin-lazy-loading*
147+ Lazy loading *lua-plugin-lazy*
148+
149+ Some users like to micro-manage "lazy loading" of plugins by explicitly
150+ configuring which commands and key mappings load the plugin.
151+
152+ Your plugin should not depend on every user micro-managing their configuration
153+ in such a way. Nvim has a mechanism for every plugin to do its own implicit
154+ lazy-loading (in Vimscript it's called | autoload | ), via `autoload/`
155+ (Vimscript) and `lua /` (Lua). Plugin authors can provide "lazy loading" by
156+ providing a `plugin /<name> .lua ` file which defines their commands and
157+ keymappings. This file should be small, and should not eagerly `require ()` the
158+ rest of your plugin. Commands and mappings should do the `require ()` .
159+
160+ Guidance:
128161
129- When it comes to initializing your plugin, assume your users may not be using
130- a plugin manager that takes care of lazy loading for you.
131- Making sure your plugin does not unnecessarily impact startup time is your
132- responsibility. A plugin's functionality may evolve over time, potentially
133- leading to breakage if users have to hack into the loading mechanisms.
134- Furthermore, a plugin that implements its own lazy initialization properly will
135- likely have less overhead than the mechanisms used by a plugin manager or user
136- to load that plugin lazily.
162+ - Plugins should arrange their "lazy" behavior once, instead of expecting every user to micromanage it.
163+ - Keep `plugin /<name> .lua ` small, avoid eagerly calling `require ()` on modules
164+ until a command or mapping is actually used.
137165
138166------------------------------------------------------------------------------
139- Defer ` require` calls *lua-plugin-lazy-loading -defer-require*
167+ Defer require() calls *lua-plugin-defer-require*
140168
141- | plugin | scripts should not eagerly `require` Lua modules.
169+ `plugin /<name> .lua ` scripts (| plugin | ) are eagerly run at startup; this is
170+ intentional, so that plugins can setup the (minimal) commands and keymappings
171+ that users will use to invoke the plugin. This also means these "plugin/"
172+ files should NOT eagerly `require` Lua modules.
142173
143174For example, instead of:
144175>lua
145- local foo = require(" foo" )
146- vim.api.nvim_create_user_command(" MyCommand" , function()
176+ local foo = require(' foo' )
177+ vim.api.nvim_create_user_command(' MyCommand' , function()
147178 foo.do_something()
148- end, {
149- -- ...
150- })
179+ end, { -- ... })
151180<
152- which will eagerly load the `foo` module and any other modules it imports
153- eagerly, you can lazy load it by moving the `require` into the command's
154- implementation.
181+ which calls `require (' foo' )` as soon as the module is loaded, you can
182+ lazy-load it by moving the `require` into the command's implementation:
155183>lua
156- vim.api.nvim_create_user_command(" MyCommand" , function()
157- local foo = require(" foo" )
184+ vim.api.nvim_create_user_command(' MyCommand' , function()
185+ local foo = require(' foo' )
158186 foo.do_something()
159187 end, {
160188 -- ...
@@ -165,23 +193,23 @@ defer `require` calls too.
165193
166194NOTE: For a Vimscript alternative to `require` , see | autoload | .
167195
168- NOTE: In case you are worried about eagerly creating user commands, autocommands
169- or keymaps at startup:
170- Plugin managers that provide abstractions for lazy-loading plugins on
171- such events will need to create these themselves.
196+ NOTE: If you are worried about eagerly creating user commands, autocommands or
197+ keymaps at startup: Plugin managers that provide abstractions for lazy-loading
198+ plugins on such events do the same amount of work. There is no performance
199+ benefit for users to define lazy-loading entrypoints in their configuration
200+ instead of plugins defining it in `plugin /<name> .lua ` .
172201
173202NOTE: You can use | --startuptime | to | profile | the impact a plugin has on
174- startup time.
203+ startup time.
175204
176205------------------------------------------------------------------------------
177- Filetype-specific functionality *lua-plugin-lazy-loading -filetype*
206+ Filetype-specific functionality *lua-plugin-filetype*
178207
179- Consider making use of | filetype | for any functionality that is specific to a
180- filetype, by putting the initialization logic in a `ftplugin/{filetype }.lua `
208+ Consider making use of ' filetype' for any functionality that is specific to
209+ a filetype, by putting the initialization logic in a `ftplugin/{filetype }.lua `
181210script.
182211
183- ------------------------------------------------------------------------------
184- Example *lua-plugin-lazy-loading-filetype-example*
212+ FILETYPE EXAMPLE
185213
186214A plugin tailored to Rust development might have initialization in
187215`ftplugin/rust.lua ` :
@@ -197,12 +225,12 @@ A plugin tailored to Rust development might have initialization in
197225 local bufnr = vim.api.nvim_get_current_buf()
198226 -- do something specific to this buffer,
199227 -- e.g. add a | <Plug> | mapping or create a command
200- vim.keymap.set("n", " <Plug> (MyPluginBufferAction)" , function()
201- print(" Hello" )
228+ vim.keymap.set('n', ' <Plug> (MyPluginBufferAction)' , function()
229+ print(' Hello' )
202230 end, { noremap = true, buffer = bufnr, })
203231<
204232==============================================================================
205- Configuration *lua-plugin-configuration *
233+ Configuration *lua-plugin-config *
206234
207235Once you have merged the default configuration with the user's config, you
208236should validate configs.
@@ -215,12 +243,18 @@ Validations could include:
215243 check, to reduce overhead.
216244
217245==============================================================================
218- Troubleshooting *lua-plugin-troubleshooting*
246+ Troubleshooting *lua-plugin-troubleshooting*
219247
220- ------------------------------------------------------------------------------
221- Health *lua-plugin-troubleshooting-health*
248+ While developing a plugin, you can use the | :restart | command to see the
249+ result of code changes in your plugin.
250+
251+ HEALTH
252+
253+ Nvim's "health" framework gives plugins a simple way to report status checks
254+ to users. See | health-dev | for an example.
222255
223- Provide health checks in `lua /{plugin}/ health.lua ` .
256+ Basically, this just means your plugin will have a `lua /{plugin}/ health.lua `
257+ file. | :checkhealth | will automatically find this file when it runs.
224258
225259Some things to validate:
226260
@@ -229,33 +263,30 @@ Some things to validate:
229263- Presence of Lua dependencies (e.g. other plugins)
230264- Presence of external dependencies
231265
232- See also | vim.health | and | health-dev | .
233-
234- ------------------------------------------------------------------------------
235- Minimal config template *lua-plugin-troubleshooting-minimal-config*
266+ MINIMAL CONFIG TEMPLATE
236267
237268It can be useful to provide a template for a minimal configuration, along with
238269a guide on how to use it to reproduce issues.
239270
240271==============================================================================
241- Versioning and releases *lua-plugin-versioning-releases *
272+ Versioning and releases *lua-plugin-versioning*
242273
243- Consider
274+ Consider:
244275
276+ - Use | vim.deprecate() | or a `--- @d eprecate` annotation when you need to
277+ communicate a (future) breaking change or discourged practice.
245278- Using SemVer https://semver.org/ tags and releases to properly communicate
246279 bug fixes, new features, and breaking changes.
247280- Automating versioning and releases in CI.
248281- Publishing to luarocks https://luarocks.org , especially if your plugin
249282 has dependencies or components that need to be built; or if it could be a
250283 dependency for another plugin.
251284
252- ------------------------------------------------------------------------------
253- Further reading *lua-plugin-versioning-releases-further-reading*
285+ FURTHER READING
254286
255- - Luarocks <3 Nvim https://github.com/nvim-neorocks/sample-luarocks-plugin
287+ - Luarocks ❤️ Nvim https://github.com/nvim-neorocks/sample-luarocks-plugin
256288
257- ------------------------------------------------------------------------------
258- Tools *lua-plugin-versioning-releases-tools*
289+ VERSIONING TOOLS
259290
260291- luarocks-tag-release
261292 https://github.com/marketplace/actions/luarocks-tag-release
@@ -265,14 +296,14 @@ Tools *lua-plugin-versioning-releases-tools*
265296 https://github.com/semantic-release/semantic-release
266297
267298==============================================================================
268- Documentation *lua-plugin-documentation *
299+ Documentation *lua-plugin-doc *
269300
270301Provide vimdoc (see | help-writing | ), so that users can read your plugin's
271302documentation in Nvim, by entering `:h {plugin} ` in | command-mode | .
272303
273- ------------------------------------------------------------------------------
274- Tools *lua-plugin-documentation-tools*
304+ DOCUMENTATION TOOLS
275305
276306- panvimdoc https://github.com/kdheepak/panvimdoc
277307
308+
278309vim:tw=78:ts=8:sw=4:sts=4:et:ft=help:norl:
0 commit comments