Lua is Neovim's embedded scripting language. Instead of just configuration, you can write plugins and automate complex behavior in Lua. Neovim's API is accessible via the vim module.
Access vim from Lua:
-- Options vim.opt.number = true vim.opt.shiftwidth = 4 -- Get option value local num = vim.opt.number:get() -- Commands vim.cmd("echo 'hello'") vim.cmd.vsplit("file.txt") -- fancy syntax -- Keybindings vim.keymap.set('n', 'gd', vim.lsp.buf.definition)
Direct access to Neovim's internal API:
-- Create a command vim.api.nvim_create_user_command('JsonFormat', function() vim.cmd("%!jq .") end, {}) -- Create an autocmd vim.api.nvim_create_autocmd("BufWritePre", { callback = function() -- do something before save end, }) -- Get buffer content local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false) -- Set buffer content vim.api.nvim_buf_set_lines(0, 0, -1, false, {"new", "lines"})
Call Vim functions from Lua:
-- File operations local file_exists = vim.fn.filereadable("path/to/file") == 1 -- String manipulation local lines = vim.fn.split("line1\nline2", "\n") -- System commands local output = vim.fn.system("ls -la")
Plugins go in ~/.config/nvim/plugin/ and auto-load on startup:
-- ~/.config/nvim/plugin/my_plugin.lua local function my_function() print("Hello from plugin") end vim.api.nvim_create_user_command('MyCommand', my_function, {})
Or in ~/.config/nvim/lua/my_plugin/ with multiple files:
~/.config/nvim/lua/my_plugin/ ├── init.lua └── utils.lua
Then require in init.lua:
require("my_plugin")
Run code on events (file open, save, etc.):
vim.api.nvim_create_autocmd("FileType", { pattern = "python", callback = function(ev) vim.keymap.set('n', '<leader>t', ':!python %<CR>', { buffer = true }) end, }) vim.api.nvim_create_autocmd("BufWritePost", { pattern = "*.py", callback = function() vim.cmd("!python -m py_compile %") end, })
pattern matches file type or name. callback is the Lua function.
Lua syntax is straightforward:
-- Loop local files = {"a.txt", "b.txt", "c.txt"} for i, file in ipairs(files) do print(file) end -- Conditionals if vim.opt.number:get() then print("Numbers on") end -- Functions local function add(a, b) return a + b end local sum = add(2, 3) -- 5
Test Lua interactively:
:lua print("hello") :lua vim.opt.number = true :luafile /path/to/script.lua
Useful for debugging.
vim.api.nvim_create_user_command('GrepTodo', function() vim.cmd("grep TODO .") vim.cmd("copen") -- open quickfix window end, {})
Then :GrepTodo searches project for TODO comments.
Lua runs in the main Neovim thread. Heavy computation blocks the editor. For intensive tasks, use external commands via vim.fn.system() or async jobs.
Lua is powerful for configuration and automation. Start with simple scripts (commands, keybindings), expand to full plugins as needed.