Tired of manually running a command in Neovim when you are editing certain files? Or want to automate more of your workflow or put some nice bells and whistles on your editor? I’ll show you how to create them yourself.
Autocommands in Neovim are a way to define custom actions or behaviors that should occur automatically in response to specific events or conditions. They can be triggered based on file types, events, or other triggers to allow you to create custom behavior within Neovim.
Warning: Autocommands are quite powerful and can obliterate your files and the text within them. Make sure you are careful when testing and use files / text that you can lose if you are doing operations that manipulates them.
Now that we have that warning out of the way, I can show you the structure of an autocommand.
Creation
You can define autocommands like this:
autocmd [group] event pattern command
group is an optional name but is useful to group your autocommands together and allow you to quickly disable, remove or refresh them.
event is a list of events that trigger your autocommand to run.
pattern is a condition you can specify to narrow down the files that your command runs against
command is the actual command that is executed when the autocommand is triggered and any patterns are matched. Note, you can do nested calls, more on that in a minute.
If you want to create an autocommand just in your local buffer.
You can use this command (buffer is not a placeholder):
:autocmd CursorHold <buffer> echo 'hold'
This autocommand will run when your cursor stops moving in your buffer.
When this happens you should see the text hold
popup in the bottom. Give it a try!
Creating autocommands on the fly is pretty handy and could be useful when debugging or other workflows but typically you will create the autocommand and place it in your init.lua
or other config file to work automagically.
Here is how you can create that same autocommand using Lua in Neovim:
Place this in your init.lua or anywhere that gets loaded in your config.
vim.api.nvim_create_autocmd('CursorHold', { command = "echo 'hold'" })
If you restart Neovim and open a buffer and wait a couple seconds you should again see hold
displayed.
Note: If you run :source %
on that file or execute the buffer local command multiple times you will see multiple entries in your autocommands (:au CursorHold
). This is not what you typically want and you can resolve this by creating an autocommand group:
local group = vim.api.nvim_create_augroup("myGroup", { clear = true })
vim.api.nvim_create_autocmd('CursorHold', { command = "echo 'hold'", group = group })
Events
There are MANY events that you can use to trigger your autocommand and you would be hard pressed to not find an event or several to use.
Here is a subset of the events you can use:
BufAdd
BufDelete
BufEnter
BufFilePost
BufFilePre
BufHidden
BufLeave
BufModifiedSet
BufNew
BufNewFile
BufReadPre
BufReadPost
If you want to trigger when you switch to a buffer you can use BufEnter
(a good point to set something for a specific filetype).
If you want to format your code before the buffer is read you can use BufReadPre
. This is useful for setting up linters and formatters.
Check out the rest of the events using :h events
.
Don’t forget that you can trigger off multiple events like this:
vim.api.nvim_create_autocmd({ "BufEnter", "BufWinEnter" }, {
group = "cursorhold",
callback = function ()
print("you got it")
end
})
Patterns
If you want to constrain your autocommand to use a specific file path or ending you can use patterns.
vim.api.nvim_create_autocmd({"BufEnter", "BufWinEnter"}, {
pattern = {"*.c", "*.h"},
command = "echo 'Entering a C or C++ file'",
})
Note: pattern is not automatically expanded, so ~ must be expanded explicitly using
vim.fn.expand
.
Commands
Now that you have configured what triggers the autocommand, what group it lives in, and what file patterns it should run against. You can now specify the command that gets run at that point in time.
In previous examples we have use command
for examples that run vim commands and callback
for examples that run lua functions. Mostly we have printed out to the screen so we can see that our commands do in fact get run.
If you use the callback function you receive a good amount of information to then do with.
Here is a list of the table you receive:
id: (number) autocommand id
event: (string) name of the triggered event |autocmd-events|
group: (number|nil) autocommand group id, if any
match: (string) expanded value of |<amatch>|
buf: (number) expanded value of |<abuf>|
file: (string) expanded value of |<afile>|
data: (any) arbitrary data passed |nvim_exec_autocmds()|
Something to note is you can call other autocommands from your autocommand, but be mindful that you are limited to 10 levels of nesting.
By default autocommands do not nest but you can pass ++nested
to use :e
or :w
.
vim.api.nvim_create_autocmd('FileChangedShell', { command = "++nested e!" })
Tips
When developing autocommands, it is useful to see more output from what is happening. Using verbose, you can see that output but heads up, it is quite noisy.
:set verbose=9
Listing Autocommands
Now that you know how to create a few autocommands, it is worth knowing how to see the autocommands you already have configured on your system.
Use the below command to see a pager view of your autocommands:
:autocmd
If you want to filter the list by autogroup or by event then specify that as the second argument.
:autocmd custom_buffer
If you have Telescope installed then you can fuzzy search over your autocommands using this command:
:Telescope autocommands
Removal / Disabling
Sometimes you need to disable or remove an autocommand.
If you want to remove an autocommand, then use this:
:au! autocommand_group
You can also use the vim.api
to clear autocommands:
vim.api.nvim_clear_autocmds("autocommand_group")
If you want to only disable all autocommands, you can use the eventignore command:
:set ei=all
If you want to disable only one autocommand, then use this:
:set ei=WinEnter,WinLeave
Note: you will need to restore eventignore to its original value after you are done using
:set ei=””
.
Examples
You now know a TON about what it takes to create autocommands, autogroups, and how to manage them on your system. The world is your oyster for what you can create but here are a couple of examples to give you ideas.
Highlight Yanked Text
If you want to visually show when you yank text then you can use this autocommand:
vim.api.nvim_create_augroup("custom_buffer", { clear = true })
vim.api.nvim_create_autocmd("TextYankPost", {
group = "custom_buffer",
pattern = "*",
callback = function() vim.highlight.on_yank { timeout = 200 } end
})
TDD Flow
A really interesting setup for using autocommands within a TDD flow is outlined in this article:
Check it out to see how you can automate running your tests after updating a file.
Conclusion
I hope this has given you a better understanding of how to create autocommands and some ideas on using them in your own Neovim setup. If you have any autocommands that you love to use, then please share in the comments! Check out this video from TJ DeVries if you want to see more on autocommands.
Here are a few other Neovim articles you might be interested in:
If you enjoy topics like this then you might also like my Youtube channel. Have a great day!