Removing whitespace in Vim

In my job, I work with JavaScript and React. We have a pretty strict eslint configuration that says a lot about what we can and can’t do with whitespace (among other things).

At first, I hated having my builds fail due to stylistic differences in opinion. Eventually I set up a linter in Vim itself so I know immediately if I’ve broken a rule, rather than waiting until the build fails. Also, with an ever-growing team, I see the value in keeping us all on the same page.

With the linter right in Vim, this next tip is not vital, but still pretty useful at times.

I wanted a way to automatically correct some of the common whitespace errors. Eslint does have a “fix” option, but I wasn’t totally comfortable with that. And the regex for fixing whitespace is pretty simple.

To remove trailing spaces at the end of a line:

1
%s/ \+$//eg

Just look for one or more spaces at the end of a line, and replace it with nothing. Ignore errors if it’s not found, and do it globally. /eg.

Multiple blank lines:

1
%s/\n\{3,\}/\r\r/eg

This one takes a bit of explanation. Our linter allows a single empty line, but not more than one. So I can’t just delete empty lines. Here, I’m looking for 3 or more newline characters. To search for a newline, use \n. Have to escape the brackets so it doesn’t search for those directly, so you get \n\{3,\} as the search term. (There are ways to setup search so it recognizes special characters like that, but for a simple one like this I didn’t bother.)

Then I want to replace that with exactly two returns. \r\r.

It seems really strange that we have to search for \n and replace with \r. But that’s how Vim rolls. When you’re searching, you look for newlines with \n. But when you’re inserting characters programatically, \n is NUL, not a newline. So you use a carriage return \r instead. I can’t guarantee that this will work in a native Windows file. But I don’t have to deal with such things currently.

Finally, our linter doesn’t like padding of code within a block. i.e.

1
2
3
4
5
6
7
8
function foo() {

notAcceptable();
}

function bar() {
acceptable();
}

This passes the single blank line test, but I need to enforce NO blank lines after an opening bracket.

1
%s/{\n\{2,\}/{\r/eg

Search for a bracket followed by two or more newlines. Replace with a bracket and a single carriage return.

So I got all these individual replacements working, but wanted to put them together in a single action. And make it possible to easily add more as needed. I decided to use a function.

1
2
3
4
5
6
function! KillWhiteSpace()
%s/ \+$//eg
%s/\n\{3,\}/\r\r/eg
%s/{\n\{2,\}/{\r/eg
endfunction
nnoremap <Leader>w :call KillWhiteSpace()<CR>

Now, two keystrokes cleans up any file nicely. And it’s clear what this is doing and easy to add more rules as needed.