4

I want all trailing whitespace in the buffers I'm editing to be highlighted in red.

Here is the autocommand I'm using:

autocmd BufEnter,WinEnter * call matchadd('Error', '\v\s+$', -1)

The matchadd() function looks for the pattern '\v\s+$' which describes trailing whitespace, and changes its color with the highlighting group Error and a -1 priority (so that 'hlsearch' whose priority is 0 can override it).

I would like to modify it so that the command is not executed in a help file. I've come up with this :

autocmd BufEnter,WinEnter * if &filetype !=? "help"
            \ | call matchadd('Error', '\v\s+$', -1)
            \ | endif

However, trailing whitespace is still colored in red even in a help file. For example, in :help 'relativenumber' below the line :

See hl-LineNr and hl-CursorLineNr for the highlighting used for the number.

... I see a red tab character on an empty line.

I've commented the autocommand, and tested the following command in various buffers (help and non help) :

if &filetype !=? "help" | call matchadd('Error', '\v\s+$', -1) | endif

It works as expected :
trailing whitespace in red in a non help file, trailing whitespace uncolored in a help file.

How to modify the autocommand so that the matchadd() function is not called in a help file ?

  • 1
    Perhaps (also) check the other way around: if it is a help file, remove the match. I think a help file is "visited" twice by Vim: first the file is opened, then a tag jump takes place, which would account for a 2nd "visit". At least, as far as I know, some autocmds get executed twice for help buffers. – VanLaser Dec 7 '15 at 11:38
2

I didn't realise that matchadd() was piling up the same highlight pattern (just with a different, incremented id), the more I was opening new buffers or simply switching between windows. Here was the output of echo getmatches() after just a few opened buffers and switching between windows:

[{'group': 'Error', 'pattern': '\v\s+$', 'priority': -1, 'id': 4}, {'group': 'Error', 'pattern': '\v\s+$', 'priority': -1, 'id': 5}, {'group': 'Error', 'pattern': '\v\s+$', 'priority': -1, 'id': 6}, ..., {'group': 'Error', 'pattern': '\v\s+$', 'priority': -1, 'id': 24}]

I suspect the only thing that my modified autocmd was doing is preventing a new match to be added when entering a help buffer. But it didn't remove all the previous ones, so maybe that's why a trailing whitespace was still colored in red even in a help buffer. Or maybe not. Maybe the highlighting is local to the window, so the previous ones were not affecting a help buffer displayed in a new window. I don't know. (*)

Besides, I wonder if the piling of the same matches would have an effect performance-wise in the long run...

Anyway, I've found a workaround using the Ex command :2match instead of the function matchadd(). Here's the code:

augroup trailing_whitespace
    autocmd!
    autocmd BufEnter,WinEnter * 2match Error /\s\+$/ |
                              \ if &filetype ==# 'help' |
                              \ call matchdelete(2) |
                              \ endif
augroup END

The advantage of :2match compared to matchadd() is that it doesn't pile up new matches, it just recreates the same one with the same id, 2, every time a buffer/window is entered.

To prevent the match to be created in a help buffer, the autocmd also executes call matchdelete(2) to delete the match whose id is 2 when the filetype is 'help' (thank you VanLaser for giving me the idea).

So far it seems to work as intended. Trailing whitespace in red everywhere except in a help buffer.

As a side note, there are actually 3 similar commands: :match, :2match, :3match which create a match whose id is respectively 1, 2 and 3.
I didn't use :match because it's more convenient to keep it untouched in case you want to create a quick match temporarily.
And I couldn't use :3match because it was already used by the script-local function Highlight_Matching_Pair() defined in /usr/share/vim/vim74/plugin/matchparen.vim.


(*) I'm not sure, but I think the matches created by matchadd() in previous windows did have an effect on a help buffer even when displayed in a new window. Otherwise the following code would work:

augroup trailing_whitespace
    autocmd!
    autocmd BufEnter,WinEnter * let m = matchadd('Error', '\v\s+$', -1) |
                              \ if &filetype ==# 'help' |
                              \ call matchdelete(m) |
                              \ endif
augroup END

But it doesn't work. A trailing whitespace is still colored in red even in a help buffer displayed in a new window.

Edit: I've just realised I could pass a fourth optional argument to matchadd() to specify the id I want, which would prevent the piling up of identical matches. So I could write something like:

augroup trailing_whitespace
    autocmd!
    autocmd BufEnter,WinEnter * call matchadd('Error', '\v\s+$', -1, 9999) |
                              \ if &filetype ==# 'help' |
                              \ call matchdelete(9999) |
                              \ endif
augroup END

But it doesn't work as intended. Besides, every time I would open a buffer or switch to another window, I would have the following error:

Error detected while processing BufEnter Auto commands for "*":
E801: ID already taken: 9999

matchadd() doesn't want to create a match whose id is already used while :2match doesn't care. So all in all, it seems :2match is a better solution for this particular autocmd.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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