Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you use buffer-local autocommands in VimScript?

I'm trying to write a snippet of VimL to allow the user to toggle the hilighting of unwanted trailing whitespace with a hotkey. (This is my first-ever Vim script, beyond copy-pasting things into my .vimrc, so … grain of salt :P)

I wish for the ‘are we currently hilighting trailing whitespace?’ to be buffer-specific state; but I'm having a lot of trouble figuring out how autocommands interact with buffers.

For instance, here's my first stab at an augroup of buffer-local autocmds:

augroup  ExtraWhitespace
   au!
   au BufEnter    <buffer=abuf> match ExtraWhitespace /\s\+$/
   au InsertEnter <buffer=abuf> match ExtraWhitespace /\s\+\%#\@<!$/
   au InsertLeave <buffer=abuf> match ExtraWhiteSpace /\s\+$/
augroup END

… unfortunately, this immediately trips up when invoked:

Error detected while processing function ToggleExtraWhitespace: 
line   19:
E680: <buffer=0>: invalid buffer number 
line   20:
E680: <buffer=0>: invalid buffer number 
line   21:
E680: <buffer=0>: invalid buffer number 
No matching autocommands

I don't understand why <abuf> is 0, when bufnr('%') is 1, or how to get the autocommands to execute for buffer 1 instead. (Of course 0 is invalid!)


For the moment, I've swapped out <buffer=abuf> for *; but this screws up the functionality of this function when there are multiple buffers loaded, and That Is Bad. So, any help figuring this out is welcome. /=

like image 323
ELLIOTTCABLE Avatar asked Aug 04 '15 22:08

ELLIOTTCABLE


1 Answers

First, I don't know how <buffer=abuf> works. The documentation for it seems to be conflicting. It appears the the behavior for <buffer=abuf> was changed/fixed with patch 7.4.637, before It was causing problems even if used correctly. <buffer=abuf> must only be used when an autocmd is running. So your function would probably have worked if you called it in VimEnter or BufAdd.


The following a modified version of what you attempted which doesn't use <buffer=abuf>

  augroup ExtraWhitespace
     autocmd! * <buffer>
     autocmd BufEnter    <buffer> match ExtraWhitespace /\s\+$/
     autocmd InsertEnter <buffer> match ExtraWhitespace /\s\+\%#\@<!$/
     autocmd InsertLeave <buffer> match ExtraWhitespace /\s\+$/
  augroup END

The first things you should notice is that au! has been replaced with autocmd! * <buffer>. au! shouldn't be there since this will remove all autocmd in the ExtraWhitespace group from all buffers. This means that you can only define it in one buffer. (autocmd! * <buffer> only deletes the autocmds in the current buffer)

The second thing you should notice is that <buffer> is used. This means that the autocmd will be created only for the current buffer when when the function is called. Buffer local autocmd must be called for each buffer that you want to define.


Other miscellaneous comments

You have

fun! HighlightExtraWhitespace()
   if exists('b:ews') && b:ews == 1
     "echom "-- Adding ExtraWhitespace hilighting"
      highlight ExtraWhitespace ctermbg=red guibg=red
   else
     "echom "-- Removing ExtraWhitespace hilighting"
      highlight clear ExtraWhitespace
   endif
endfun
au ColorScheme * call HighlightExtraWhitespace()

Highlighting is global, so clearing it in one buffer is going to remove the highlight group everywhere. So its better to just leave the highlighting in place and redefine it every time the colorscheme changes.

autocmd ColorScheme * highlight ExtraWhitespace ctermbg=red guibg=red

It is recommended to use the long form of command names in scripts. (Short form used only for typing). The long form is more readable and easily identifiable, so au would be come autocmd.

like image 187
FDinoff Avatar answered Oct 19 '22 23:10

FDinoff