Enhancing Neovim Plugin Documentation and Readability with Lua Type Annotations: lazydocker.nvim Case Study
Table of Contents
Introduction#
In the world of Neovim plugin development. One of superpowers enabled by the Lua language
in Neovim is type annotations using EmmyLua-style comments (---@).
These annotations supercharge documentation, IDE integration, and code readability.
In lazydocker.nvim, a plugin that embeds LazyDocker
into a Neovim floating window, I extensively used these annotations.
Lua Type Annotations#
Lua is dynamically typed, but Neovim’s LSP (via nvim-lspconfig and emmy-lua) supports EmmyLua annotations:
---@class MyClass
---@field field string A description.
---@param param string Input param.
---@return boolean Success?
function myFunc(param) end
These generate:
- Hover docs in Neovim (
K) - Autocomplete for fields/methods
- Vim help pages (
:help lazydocker.nvim) - Type checking warnings
Type Hierarchy in lazydocker.nvim#
The plugin defines a rich type system:
---@class LazyDocker
---@field config LazyDocker.Config Module config table. See |LazyDocker.config|.
---@field setup fun(config?: LazyDocker.Config) Module Setup. See |LazyDocker.setup()|.
...
Nested Types:
---@class LazyDocker.Config
---@field window LazyDocker.WindowConfig
---@class LazyDocker.WindowConfig
---@field settings LazyDocker.WindowSettings
---@class LazyDocker.WindowSettings
---@field width number Width of the floating panel...
---@field height number Height...
---@field border string Style...
---@field relative string Layout relative to...
Aliases for enums:
---@alias LazyDocker.Engine string only accepts the values 'podman' and 'docker'
Enhancing Readability#
Without types:
-- What is this? Magic table?
local config = { window = { settings = { width = 0.618 } } }
require('lazydocker').setup(config)
With types (hover config generates a full schema!):
local config: LazyDocker.Config = {
window = {
settings = {
width = 0.618, -- 0-1 percentage
border = 'rounded', -- Valid: 'rounded', 'single', etc.
}
}
}
Validation helpers reference types implicitly:
function H._is_percentage(a) -- Ensures 0 < width/height <= 1
vim.validate({ ['width'] = { settings.width, H._is_percentage, '0-1' } })
Supercharged IDE Features#
Autocomplete Everywhere:
- Type
LazyDocker.config.window.settings.generates a popup withwidth|height|border|relative. LazyDocker.open({ engine = 'generates an autocompletion with'docker'|'podman'.
- Type
Hover Documentation (hit
K):- On
LazyDocker.open: Full@usageexamples + param types. - Cross-references like
|LazyDocker.config|link to help sections.
- On
Error Prevention:
- LSP warns:
opts.enginemust be'docker'|'podman'. - Invalid
border = 'invalid'→ squiggles + message.
- LSP warns:
Help Integration:
* |LazyDocker.types| * |LazyDocker.setup|:help LazyDocker.typesrenders the@classdocs beautifully.