Autocommands
Autocommands run Lua functions (or Vimscript) in response to Neovim events. They automate behaviors like formatting on save, highlighting on yank, and applying filetype-specific settings.
Core Idea
An autocmd says: "When event happens with pattern, run callback." Events include BufWritePre, BufEnter, FileType, InsertLeave, and dozens more.
The Lua API
vim.api.nvim_create_autocmd(event, {
group = augroup_id, -- optional: put in an augroup
pattern = "*.lua", -- file pattern or "*"
callback = function(args)
-- args.buf, args.file, args.match, etc.
end,
desc = "Description",
})
Augroups — Preventing Duplicate Autocmds
Always use augroup to group related autocmds. The { clear = true } option removes any existing autocmds in the group (prevents duplicates on config reload):
local augroup = vim.api.nvim_create_augroup
local autocmd = vim.api.nvim_create_autocmd
local my_group = augroup("MyGroup", { clear = true })
autocmd("BufWritePre", {
group = my_group,
pattern = "*",
callback = function()
-- runs before every save
end,
})
Essential Autocommands
1. Highlight on Yank
autocmd("TextYankPost", {
group = augroup("highlight_yank", { clear = true }),
callback = function()
vim.highlight.on_yank({
higroup = "IncSearch",
timeout = 150,
})
end,
desc = "Highlight yanked text",
})
2. Return to Last Cursor Position
autocmd("BufReadPost", {
group = augroup("last_cursor", { clear = true }),
callback = function()
local mark = vim.api.nvim_buf_get_mark(0, '"')
local lcount = vim.api.nvim_buf_line_count(0)
if mark[1] > 0 and mark[1] <= lcount then
pcall(vim.api.nvim_win_set_cursor, 0, mark)
end
end,
desc = "Return to last cursor on open",
})
3. Remove Trailing Whitespace on Save
autocmd("BufWritePre", {
group = augroup("trim_whitespace", { clear = true }),
pattern = "*",
callback = function()
local pos = vim.api.nvim_win_get_cursor(0)
vim.cmd([[%s/\s\+$//e]])
vim.api.nvim_win_set_cursor(0, pos)
end,
desc = "Remove trailing whitespace on save",
})
4. Auto-format on Save
autocmd("BufWritePre", {
group = augroup("auto_format", { clear = true }),
pattern = { "*.lua", "*.js", "*.ts", "*.py", "*.go" },
callback = function()
vim.lsp.buf.format({ async = false, timeout_ms = 3000 })
end,
desc = "Format on save",
})
5. Filetype-Specific Settings
autocmd("FileType", {
group = augroup("filetype_settings", { clear = true }),
pattern = { "python" },
callback = function()
vim.bo.tabstop = 4
vim.bo.shiftwidth = 4
vim.bo.expandtab = true
end,
})
autocmd("FileType", {
group = augroup("markdown_settings", { clear = true }),
pattern = { "markdown", "text" },
callback = function()
vim.wo.wrap = true
vim.wo.linebreak = true
vim.wo.spell = true
vim.opt_local.spelllang = "en_us"
end,
})
6. Close Certain Filetypes with q
autocmd("FileType", {
group = augroup("close_with_q", { clear = true }),
pattern = {
"qf", "help", "man", "notify",
"lspinfo", "spectre_panel", "checkhealth",
},
callback = function(event)
vim.bo[event.buf].buflisted = false
vim.keymap.set("n", "q", "<cmd>close<cr>", {
buffer = event.buf,
silent = true,
})
end,
})
7. Auto-reload Files Changed Externally
autocmd({ "FocusGained", "BufEnter", "CursorHold", "CursorHoldI" }, {
group = augroup("auto_reload", { clear = true }),
callback = function()
if vim.fn.mode() ~= "c" and
vim.fn.getcmdwintype() == "" and
not vim.bo.modified then
vim.cmd("checktime")
end
end,
desc = "Reload file when changed externally",
})
8. Equalize Splits on Window Resize
autocmd("VimResized", {
group = augroup("equalize_splits", { clear = true }),
callback = function()
vim.cmd("tabdo wincmd =")
end,
})
Listing and Deleting Autocmds
-- List all autocmds
:autocmd
-- List autocmds in a group
:autocmd MyGroup
-- Delete an autocmd (Lua)
vim.api.nvim_del_autocmd(autocmd_id)
-- Clear a group
vim.api.nvim_clear_autocmds({ group = "MyGroup" })
Common Events Reference
| Event | When it fires |
|---|---|
BufWritePre | Before writing a buffer |
BufWritePost | After writing a buffer |
BufEnter | When entering a buffer |
BufLeave | When leaving a buffer |
BufReadPost | After reading a buffer |
FileType | After filetype is set |
InsertEnter | Entering Insert mode |
InsertLeave | Leaving Insert mode |
TextYankPost | After yanking text |
VimResized | Terminal window resized |
FocusGained | Window gains focus |
CursorHold | Cursor held still (updatetime) |
LspAttach | After LSP attaches to buffer |