Vim Terminator
There are vim plugins for nearly everything, but when it comes to actually running your code in vim the options are rather limited. Hence, I created vim-terminator, an asynchronous code running plugin for vim (version 8 and above) and neovim.

Life without the terminator
Before creating this plugin, I ran my code in several ways, each of which had its shortcomings.
Option 1: The vim command line
Commands can be executed in a shell by using command mode in vim and
prefixing with an exclamation mark. For example
:!echo "hello"
will run the command
echo "hello"
and the result will appear in a temporary
window (which vanishes after pressing any key).
I used this for a while and set up some key bindings to run my file
using things such as
nnoremap <leader>r :!python3 %<CR>
to run the
current file using python. This is the worst solution. You have to wait
for the entire process to finish before being able to see your editor
again, and the second you press a key you can no longer view the
output.
Option 2: Putting vim in the background
By pressing ctrl-z
, the vim process is put in the
background. Then you can run your code in the terminal vim is running
in. To get vim back you can just type the command fg
. This
may or may not be an improvement from the vim command line.
Option 3: Tmux
Tmux is pretty amazing. For a while I had vim in a tmux split and a terminal in the other pane. Then you can switch between vim and the terminal to run the code. My complaint with this solution is that you have one more set of key bindings to keep track of, and tmux can add a layer of complexity that does not need to exist. I ran into issues with python virtual environments not starting correctly and terminal colors not being properly displayed.
Option 4: Built in vim terminal
In vim8 or neovim there is a built in terminal! The terminal emulator
inside of vim is pretty good as compared to my experience with emacs… My
one complaint with the built-in vim terminal is having to navigate to
and from it. To get out of insert mode inside the terminal, you must
press the key combination <c-\><c-n>
. Then of
course you can navigate back to your current buffer from normal mode
using shortcuts such as <c-^>
, but this becomes
clumsy.
Vim-terminator makes the terminal experience inside of vim more pleasant by allowing you to send text to the terminal rather than having to manually type it!
Option 5: Dispatch
I was a big fan of Tim Pope’s vim-dispatch plugin, and I still supplement my vim-terminator experience with dispatch. The two features I like about dispatch are that it is asynchronous and it puts errors into the quickfix window.
I first found the quickfix window when using the vimtex plugin for editing \(\LaTeX\). It puts the errors and warnings from the compiler log into a small (quickfix) window which allows you to conveniently jump to them regardless of the file they are in.
In short, vim-dispatch basically makes an asynchronous version of the
built in :make
command. The :make
command
along with :compiler
, :makeprg
, and
errorformat
may take a decade to understand entirely. The
key takeaway is that you can usually just set :compiler
to
one of the compilers provided by vim and the :makeprg
to
the command you want to run and everything works nicely. The other nice
feature is that :Make
allows you to use a Makefile if your
build is more complicated than just compiling your current file.
Vim-dispatch is great when you do not want to wait for a process to
finish and you only want to see the output if there are errors. This
works well for compiling programs and for runnings tests. Often times
when writing code, I want to quickly run my current file
(asynchronously) and see the output immediately. Trying
to accomplish this with dispatch for a language like python is
impossible for all practical purposes. For instance, to keep the
quickfix window open after running a python program with dispatch, one
needs to make the file executable and run it with a command like
:Dispatch ./%
such that there is not an
errorformat
hiding the quickfix window at the end of the
job. The quickfix window was not designed to be used in this way.
Life with the terminator
For me, vim-terminator fixes all of these problems. It runs asynchronously, it puts the output of your code in an output buffer that always opens, it automatically sets the command to run for you based on file type, and it puts the errors in the quickfix window. Plus it has many additional features for working with the vim terminal, which is where the plugin gets its name.
One final interesting observation is that vim-terminator can actually run code faster than in the terminal or using vim-dispatch given that there is a non-trivial amount of STDOUT. This has to do with scrolling. As a simple test, the following code was run in the output buffer, the vim terminal, and in the quickfix window using dispatch.
#!/usr/bin/env python3
for i in range(1000000):
print('test', i)
Output buffer speed test
The command <leader> rf
was used (which runs
python test.py
) and resulted in:
[Done] in 8.222829 seconds
Vim terminal speed test
The command time ./test.py
was used and resulted in:
./test.py 4.64s user 3.01s system 55% cpu 13.835 total
Quickfix speed test
The command :Dispatch time ./test.py
was used and
resulted in:
./test.py 4.41s user 3.07s system 53% cpu 13.888 total
Summary
Location | Run Time (s) |
---|---|
Output Buffer | 8.2 |
Terminal | 13.8 |
Quickfix | 13.9 |