In Editor Linting with Syntastic

In this post I’m going to talk about setting up Syntastic in Vim, and why it’s an important development tool. Syntastic is plugin that runs files through external syntax checkers (linters). It’s capable of using built-in Vim features (statusline, sign, location-list) to show potential syntax and style issues.

This screenshot from the Syntastic developer (Martin Grenfell) shows what Syntastic in Vim terminology.

Syntastic Vim

When you’re learning a new library, framework, or even programming language, linting can actually help you learn. I used to think strict linting got in the way and demotivated people, but in-line, helpful linting can not only help improve code quality, but also aid learning.

Background

Over the last year I’ve been using the React library for creating user interfaces. One area that React can help with is the way data flows in the UI, and to get real benefits from this is to understand React’s best practices. It’s hard to learn best practices at the same time as learning new libraries, so what do you do?

I noticed a colleague had a great solution to this: Neovim and Neomake. In this post I’m going to talk about the Vim equivalent, but I may write another post later about Neovim. The advantage of Neomake over Syntastic is Neovim allows it to run asynchronously, so you don’t get any input lag when it runs.

Here are just some of the benefits that linting gave us:

  • We learned about React.PropTypes, which let us "strongly type" our React components and move to the Redux pattern
  • We discovered new idioms: the linter trained us how to lay out React classes according to popular community standards
  • Our code become similar, which helped with pull requests, merges, and collaboration in general

The best thing about all of this was the linter’s advice appears in the editor, with tips on how to fix the issues. It’s much less intimidating than the older style of scolding the programmer. I’ve also configured Syntastic to use shellcheck, which has helped me significantly improve my shell scripts.

Setting up Syntastic

Install Syntastic with your favourite plugin manager. The readme has some recommended settings, but I think you’ll like mine:

set statusline+=%#warningmsg#
set statusline+=%{SyntasticStatuslineFlag()}
set statusline+=%*
let g:syntastic_always_populate_loc_list = 1
let g:syntastic_loc_list_height = 5
let g:syntastic_auto_loc_list = 0
let g:syntastic_check_on_open = 1
let g:syntastic_check_on_wq = 1
let g:syntastic_javascript_checkers = ['eslint']
let g:syntastic_error_symbol = '❌'
let g:syntastic_style_error_symbol = '⁉️'
let g:syntastic_warning_symbol = '⚠️'
let g:syntastic_style_warning_symbol = '💩'
highlight link SyntasticErrorSign SignColumn
highlight link SyntasticWarningSign SignColumn
highlight link SyntasticStyleErrorSign SignColumn
highlight link SyntasticStyleWarningSign SignColumn

Here's what these settings do:

  • Hide the error list (location-list) by default. You can show it with :Error
  • Make Syntastic use ESLint for JavaScript. I found this was currently the best JavaScript linter
  • Add custom emoji for error symbols with some nicer colours — by default errors are shown for each line using error symbols with background colours

I find the combination of sign column symbols with a hidden error list works well. I don't like the way the error list wastes vertical space, and if you move the cursor over a line with an error it'll show the corresponding advice in the statusline.

Here's what my settings look like:

Syntastic

ESLint

Setting up ESLint is more work than I expected, which is what motivated me to write this post. The first thing to do is to install eslint.

npm i -g eslint

ESLint can use a project-specific configuration file, or a user-specific dotfile. It can also combine options from both of these. In our project we've opted to use user-specific files, because we found installing the required ESLint plugins changed over time: someone set it up two weeks before me and the dependencies had changed already. In a Node project you could make these plugins part of your devDependencies, so if you're set on forcing your team to use ESLint then that's probably the best option.

Here's a quick start guide for ESLint/React:

  1. Get my eslint.json with some pretty cool React plugins
  2. Install the plugins

At the time of writing, these are the npm packages that you'll need:

npm i -g estraverse estraverse-fb eslint-plugin-react babel-eslint

If you run eslint your-file.jsx you should see some linter output. If the required plugins haven't been installed then it'll show an error. For example:

Cannot find module 'babel-eslint' from '/Users/alex/.nvm/versions/node/v5.6.0/lib/node_modules

Keep running npm install with each plugin until you get it working.

Use Vim

Now eslint is capable of checking a JavaScript file, try it out in Vim! If you can't seem to find any errors in the sign column, try typing :Errors.

Help! ESLint stopped working!

If you start Vim one day and you can't see any errors when you know there should be some, try running your linter from the command-line.

eslint file.jsx

I recently ran into this issue when I upgraded Node and had to upgrade some of my ESLint plugins.

You can also run :SyntasticInfo to see what filetype Syntastic thinks the file is, and what linter it'll run (if any).