chapters/14.markdown @ a16e1fecfe07 default tip

Be clear
author Steve Losh <steve@stevelosh.com>
date Mon, 27 Mar 2017 13:10:55 +0000
parents 4fa876d7523c
children (none)
Autocommand Groups
==================

A few chapters ago we learned about autocommands.  Run the following command:

    :::vim
    :autocmd BufWrite * :echom "Writing buffer!"

Now write the current buffer with `:write` and run `:messages` to view the
message log.  You should see the `Writing buffer!` message in the list.

Now write the current buffer again and run `:messages` to view the message log.
You should see the `Writing buffer!` message in the list twice.

Now run the exact same autocommand again:

    :::vim
    :autocmd BufWrite * :echom "Writing buffer!"

Write the current buffer one more time and run `:messages`.  You will see the
`Writing buffer!` message in the list *four* times.  What happened?

When you create an autocommand like this Vim has no way of knowing if you want
it to replace an existing one.  In our case, Vim created two *separate*
autocommands that each happen to do the same thing.

The Problem
-----------

Now that you know it's possible to create duplicate autocommands, you may be
thinking: "So what?  Just don't do that!"

The problem is that sourcing your `~/.vimrc` file rereads the entire file,
including any autocommands you've defined!  This means that every time you
source your `~/.vimrc` you'll be duplicating autocommands, which will make Vim
run slower because it executes the same commands over and over.

To simulate this, try running the following command:

    :::vim
    :autocmd BufWrite * :sleep 200m

Now write the current buffer.  You may or may not notice a slight sluggishness
in Vim's writing time.  Now run the command three more times:

    :::vim
    :autocmd BufWrite * :sleep 200m
    :autocmd BufWrite * :sleep 200m
    :autocmd BufWrite * :sleep 200m

Write the file again.  This time the slowness will be more apparent.

Obviously you won't have any autocommands that do nothing but sleep, but the
`~/.vimrc` of a seasoned Vim user can easily reach 1,000 lines, many of which will
be autocommands.  Combine that with autocommands defined in any installed
plugins and it can definitely affect performance.

Grouping Autocommands
---------------------

Vim has a solution to the problem.  The first step is to group related
autocommands into named groups. 

Open a fresh instance of Vim to clear out the autocommands from before, then run
the following commands:

    :::vim
    :augroup testgroup
    :    autocmd BufWrite * :echom "Foo"
    :    autocmd BufWrite * :echom "Bar"
    :augroup END

The indentation in the middle two lines is insignificant.  You don't have to
type it if you don't want to.

Write a buffer and check `:messages`.  You should see both `Foo` and `Bar`.  Now
run the following commands:

    :::vim
    :augroup testgroup
    :    autocmd BufWrite * :echom "Baz"
    :augroup END

Try to guess what will happen when you write the buffer again.  Once you have
a guess in mind, write the buffer and check `:messages` to see if you were
correct.

Clearing Groups
---------------

What happened when you wrote the file?  Was it what you expected?

If you thought Vim would replace the group, you can see that you guessed
wrong.  Don't worry, most people think the same thing at first (I know I did).

When you use `augroup` multiple times Vim will *combine* the groups each time.

If you want to *clear* a group you can use `autocmd!` inside the group.  Run the
following commands:

    :::vim
    :augroup testgroup
    :    autocmd!
    :    autocmd BufWrite * :echom "Cats"
    :augroup END

Now try writing your file and checking `:messages`.  This time Vim only echoed
`Cats` when you wrote the file.

Using Autocommands in Your Vimrc
--------------------------------

Now that we know how to group autocommands and clear those groups, we can use
this to add autocommands to `~/.vimrc` that don't add a duplicate every time we
source it.

Add the following to your `~/.vimrc` file:

    :::vim
    augroup filetype_html
        autocmd!
        autocmd FileType html nnoremap <buffer> <localleader>f Vatzf
    augroup END

We enter the `filetype_html` group, immediately clear it, define an autocommand,
and leave the group.  If we source `~/.vimrc` again the clearing will prevent
Vim from adding duplicate autocommands.

Exercises
---------

Go through your `~/.vimrc` file and wrap *every* autocommand you have in groups
like this.  You can put multiple autocommands in the same group if it makes
sense to you.

Try to figure out what the mapping in the last example does.

Read `:help autocmd-groups`.