I would like to execute a certain function every time I leave a buffer associated with C++, and another function every time I enter a C++ buffer. I came up with this so far:

" Buffer Leave
augroup myBufferLeave
    autocmd BufLeave *.cpp,*.c,*.h call s:ExecuteLeave()
augroup END

" Buffer Enter
augroup myBufferEnter
    autocmd BufEnter *.cpp,*.c,*.h call s:ExecuteEnter()
augroup END

Another alternative is to hook into the global BufEnter event and set a buffer variable or check the current &ft and execute the appropriate function:

autocmd BufEnter * if &ft = 'cpp' |
    \ call s:ExecuteEnter() |
    \ endif

autocmd BufLeave * if &ft = 'cpp' |
    \ call s:ExecuteLeave() |
    \ endif

Is there a cleaner way to do this? Ideally, without tapping into the * global buffer events. Ideally, I would like to use something like this:

 autocmd BufLeave cpp call s:ExecuteLeave()
 autocmd BufEnter cpp call s:ExecuteEnter()

Is there a way to pack the *.cpp,*.c,*.h condition into one single definition such as cpp? The cpp definition is a FileType, but file-types are not triggered on BufEnter and BufLeave. If one needs to add another file extension, such as *.CXX for example, the list will become bloated eventually *.cpp,*.c,*.h, *.CXX, *.C, and a bit hard to maintain.

  • 1
    Possible X/Y problem. What exactly are you trying to do? Have buffer specific mappings (See :h :map-local), buffer commands (See :h :command-buffer), or buffer local settings (See :h setlocal)? Apr 7, 2016 at 20:53
  • 1
    I would like to be able to come up with a buffer enter/leave event that is not depending on long file extension lists. Ideally, dealing with the file extensions problem in a 'ftdetect' script, and put ambiguous file extensions such as '*.h, *.C, *.CXX' into a 'cpp' file type, so we keep adding to these in order to include new extensions into the defined file type and on the 'BufEnter' and 'BufLeave' side we just use the FileType tag, such as 'cpp' instead of a long list of constantly growing extensions.
    – mbilyanov
    Apr 7, 2016 at 21:37
  • 1
    I understand what the kind of autocmd pattern you are trying to craft (Spoiler: your autocmd * if &ft method is the correct way to do this). My question to you is what are your ExecuteEnter()/ExecuteLeave() supposed to be doing? More than likely you are trying to add buffer specific mappings/commands/settings, of which there are better ways methods. Apr 7, 2016 at 21:46
  • 1
    I would like to set an option, set completeopt-=preview when entering C++ or C buffers and set completeopt+=preview when leaving C++ or C buffers. But nowadays, the C/C++ files may have a very rich variety of extensions, writing down all of these seems too laborious and not very smart.
    – mbilyanov
    Apr 7, 2016 at 21:55

1 Answer 1


As the completeopt is a global option, you are correct in that you need a way to toggle the preview setting. I suggest you do this via the BufEnter autocmd with a * as the pattern.

augroup TogglePreview
  autocmd Filetype,BufEnter * execute 'set completeopt'.(&ft == 'cpp' ? '+' : '-').'=preview'
augroup END

The idea is that the autocmd uses 'filetype' upon entering a new buffer or settings the buffer's 'filetype' to decide to turn on/off the preview option.

You may want to consider using :pclose to close the preview window as well.

For more help see:

:h :au
:h BufEnter
:h 'completeopt'
:h :exe
:h :pclose
  • 1
    Cool. It seems like this has to be an '*' event. Why would you prefer WinEnter over BufEnter? Also, why do we need the 'FileType' in there? Is not WinEnter (or BuffEnter) enough? Thanks.
    – mbilyanov
    Apr 7, 2016 at 22:29
  • 1
    Using BufEnter is probably better (I have changed the post). The reason I use FileType event is in case you a buffer's 'filetype' changes. Apr 7, 2016 at 22:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.