Thu 07 March 2019

Vim, ALE, Docker, and Per-Project Linting

I've been using Vim for a little over ten years now. Up until Vim 8, I'd go so far as to say little changed for me... but Vim 8 actually changed the game in a pretty big way. The introduction of asynchronous jobs that can run in the background enables functionality like code linting and completion that don't block the editor, a rather stark contrast to the old days. In fact, I outright didn't bother with code completion and the like prior to Vim 8 - it was never fast enough and just left me too annoyed to care.

Anyway, thanks to this new functionality, we can use projects like ALE to provide smooth linting, autocompletion, fixing, and so on. Setting up this and other Vim plugins is a bit outside the scope of this post, but I'd highly recommend it if you haven't tried it. ALE includes support for LSP (language-server-protocol), originally developed by Microsoft and now supported by a litany of editors and IDEs. This support has made Vim feel like far less of a black-box at points!

ALE and Docker

One thing I ran into when setting ALE up was that various projects have their own rules. For example, a Japanese company I help has some rather peculiar style rules for their Python codebase. I recently converted their infrastructure to a Docker-based architecture, and as a result all Python code executes inside a virtual machine (at least, insofar as MacOS/Windows are concerned - Linux users might have a slightly easier time here!).

In most cases, this is not too big of a problem - however, this particular case means that tools like flake8 are running inside the VM, and not in the userspace where you'd be running Vim. In the issues I glanced over, the author of ALE recommends just running Vim over SSH into the VM, which can be an alright solution... albeit a bit clunky, given your setup for Vim runs on your local machine. We really just need a way to communicate between the two layers, right?

This is actually possible with just a bit of extra configuration work. We'll need two things before we can make it work, though:

  • If you haven't already, I recommend setting up your Vim installation so that it supports some kind of local .vimrc setup. I use embear/vim-localvimrc and whitelist the projects I know are safe, but you do you.
  • A custom shell script to act as the bridge between Docker and the host environment.

The Shell Script

This is much simpler than you'd think! Somewhere in your project, edit and throw the following:

#!/bin/bash
docker-compose exec -T {{ Your docker env name here }} flake8 $@

This is inspired by acro5piano's post over on qiita, but fixed up slightly to work with what I presume are recent changes in Docker and/or ALE. Notably, our command has to specify -T to stop Docker from allocating a pseudo TTY. Save this and mark it as executable, and ensure your Docker environment is running if you want ALE to report errors.

(I also figured I'd throw this post up in English, just so the knowledge is a bit more freely available)

Local .lvimrc Configuration

With the shell script in place, we just need to instruct ALE on how to call flake8. If you're using vim-localvimrc, you can throw a .lvimrc in your project root with the following:

let g:ale_python_flake8_executable = '/path/to/flake8/shell/script'

Provided you did all the above correct, flake8 should now be properly reporting to ALE. You'd need to do this setup per-project, but to be honest I don't find it that annoying, as I find Docker is worth it over the old-school Virtualenv solutions. If you know of a better way to do this, I'm all ears!

Ryan around the Web