I prepared these notes as part of the meetup event (Vimprovement 5), but they might be useful even if you haven’t joined.
Autocommands are the way to execute any vim actions (like setting an option or mapping a key) in response to various events. Events recognised by vim include writing or reading a file, detecting a filetype, and a lot more.
Autocommands can be set by plugins, or by yourself in your vimrc. The most common category of user-defined autocommands is setting options for particular filetype.
You need to wrap your autocommands in the augroup sandwich:
augroup GROUP_NAME autocmd! <here go your autocommands> augroup END
This makes sure that your vimrc can be safely sourced multiple times. Without augroup and autocmd! part, your autocommands would not be cleared, and effectively duplicated, which can cause problems.
Here’s how to set different options for different filetypes:
augroup GROUP_NAME autocmd! autocmd FileType python set local shiftwidth=2 autocmd FileType c set local shiftwidth=8 augroup END
The general syntax is:autocmd <event> <pattern> <command>
To see all the events recognized by vim, run :h autocommand-events
. There’s over one hundred of them!
<pattern>
may have different meaning for different events. For reading- and writing-related events, it’s usually a filename. Another example is FileType
event; with it, <pattern>
is a filetype, like javascript
. If an event does not give any meaning to <pattern>
, you still need to put something between <event>
and <command>
– use *
in that case.
Here are some more exotic examples of autocommands, with commands explaining what they are doing:
augroup VIMPROVEMENT autocmd! " Reload my vimrc everytime I save it. autocmd BufWritePost ~/.vimrc source % | redraw | echo "Reloaded vimrc!" " Open temporary, readonly buffer with text extracted from a pdf file. autocmd BufReadPost *.pdf \ edit <afile>:r | \ set buftype=nofile | \ set bufhidden=delete | \ set readonly | \ %!pdftotext <afile> - " Open temporary, readonly buffer with un-minified JavaScript. autocmd BufReadPost *.min.js \ edit <afile>:r:r | \ set buftype=nofile | \ set bufhidden=delete | \ set readonly | \ %!unminify <afile> - " Project-specific settings - run prettier on JavaScript files, but only in that directory (recursively) autocmd BufWritePost /Users/mdr/proj/vimprovement/5_2020_12_14/project/*.js silent !npx prettier --write autocmd BufWritePost /Users/mdr/proj/vimprovement/5_2020_12_14/project/*.js redraw! " Save buffer when idle (only when there are changes) autocmd CursorHold * update augroup END
The PDF trick requires pdfutils
command to be available (brew install poppler
to get it, if you’re on MacOS with Homebrew).
The JavaScript trick requires the unminify
command to be available (npm i -g unminify
).
If you want to check out all my autocommands, see this gist.
Other things, not mentioned yet (you can learn about them in :h autocommands
):
<buffer>
- Using multiple events and multiple patterns in a single autocmd
- Built-in gzip functionality as an example of sophisticated use of autocommands
Examples shared by participants
Here are autocommand examples shared in the chat during the event. Thank you!
From Nikhil – setting mappings for Python files:
autocmd FileType python nnoremap <silent> <leader>r :w !python3.8<CR> autocmd FileType python vnoremap <silent> <leader>r :w !python3.8<CR> autocmd FileType python nnoremap <silent> <leader>i :!bpython -q -i %<CR>
From Lucas – example of alternative to autocmd for filetype-specific configuration:
$ cat ftplugin/python.vim setlocal formatprg=black\ --quiet\ - nnoremap <buffer> <F5> :up\|!python "%"<CR> nnoremap <buffer> <F7> mfgggqG`fzz
From Andres – toggle relativenumber
option when entering and leaving insert mode:
au InsertEnter * :set norelativenumber au InsertLeave * :set relativenumber
From Andres – session setup when entering and leaving vim:
function! MakeSession() let b:sessiondir = $HOME . "/.vim/sessions" . getcwd() if (filewritable(b:sessiondir) != 2) exe 'silent !mkdir -p ' b:sessiondir redraw! endif let b:filename = b:sessiondir . '/session.vim' exe "mksession! " . b:filename endfunction function! LoadSession() let b:sessiondir = $HOME . "/.vim/sessions" . getcwd() let b:sessionfile = b:sessiondir . "/session.vim" if (filereadable(b:sessionfile)) exe 'source ' b:sessionfile else echo "No session loaded." endif endfunction au VimEnter * nested if argc() == 0 | :call LoadSession() | endif au VimLeave * if argc() == 0 | :call MakeSession() | endif
From Nick – running media files with default programs:
(OpenSystemFile would be a operating-system specific function that runs a default program associated with a filetype)
augroup FILE_OPEN_GROUP autocmd! autocmd BufEnter *.jpg call OpenSystemFile() autocmd BufEnter *.png call OpenSystemFile() autocmd BufEnter *.gif call OpenSystemFile() autocmd BufEnter *.pdf call OpenSystemFile() augroup END
From Andres – highlight yank:
au TextYankPost * silent! lua vim.highlight.on_yank {higroup="IncSearch", timeout=300}
From Nazar – automatically rebalance windows on vim resize:
autocmd VimResized * :wincmd =
From Martin – project-specific options:
au BufNewFile,BufRead /private/var/*/gopass* setlocal noswapfile nobackup noundofile