neovim and go

Vim has had great Go support for a long while. Neovim is a fork of vim with some interesting goals. For me personally, neovim offers a couple of benefits over vim. Firstly its completion engine works and works fast. Secondly, there’s now a go debugger plugin which works for neovim only.

In this post I’ll talk about:

  • Background: vim, neovim and vim-go
  • Comfortably migrating from vim to nvim
  • Fast autocompletion with deoplete
  • Debugging with vim-godebug and delve

Vim and neovim

neovim is a fork of vim, with a cli command nvim. To begin with its most attractive features were its asynchronous plugins, and its embedded terminal. When vim8 came out with async support a few months back, that edge seemed to diminish, but for me it still retains compelling advantages.

Note, I’m not here to discuss the relative merits of the two projects or their communities — I’m more sharing my preferences and tips. Also note that I’ve mostly used neovim for the past year, so my vim talk might be out of date.

vim-go

The wonderful vim-go plugin, by the venerable Fatih Arslan, offers a great collection of features, whether you’re using vim or neovim. I don’t think there’s a comparable plugin in the ecosystem, so IMO just use it. vim-go offers all kinds of goodness:

  • Format-on-save — by default go-fmt, but I’d recommend goimports instead:
let g:go_fmt_command = "goimports"
  • Refactoring with :GoRename (try the godoctor plugin for more refactoring features)
  • Execution/testing with :GoTest , :GoInstall and :GoRun
  • Source code analysis with :GoDef, :GoReferrers and :GoImplements
  • Lots more

There’s a couple of other refactorings which are available through another plugin, godoctor.vim , but otherwise the only other stuff I use is neovim-specific.

Migrating to neovim

Installing neovim should be straightforward for most platforms. I use it on Linux, Mac and occasionally even Android. Installation is the easy part.

Vim config can be a tricksy business at the best of times, so I appreciate if the move to neovim is offputting. I had 2 key questions:

1. Is it feasible to share config files between the 2 editors, or should they be kept separate?

I have found it just fine to share config between my vim and neovim. You can do this with symlinks and a couple of if statements. See ‘sharing config’ below.

2. Should I alias vim to nvim?

Eventually, yes. I went there. But while you’re getting used to the little differences, I wouldn’t override the vim, vi or $EDITOR commands right away — only once you’re confident that nvim is working for you. The neovim docs give platform-specific advice, once you’re ready.

Sharing config with vim

In my experience it’s worked fine to share config between vim and nvim. This also makes it easier to share my config across different computers.

Recommendation: just symlink your existing .vimrc to init.vim:

ln -s ~/.vimrc ~/.config/nvim/init.vim

You’ll need to put a couple of if statements into your .vimrc like. I’ve done it once for loading plugins, and again for any other config differences — just a couple of things really.

Plugin management

I use vim-plug by Junegunn Choi. It’s fast because it makes use of nvim’s (and equally vim 8’s) async processing. Installation instructions here. You can use other plugin managers, the syntax tends to be similar for each.

This .vimrc snippet is my relevant vim-plug config for go:

call plug#begin('~/.vim/plugged')
Plug 'fatih/vim-go' # Amazing combination of features.
Plug 'godoctor/godoctor.vim' # Some refactoring tools
if !has('nvim')
Plug 'maralla/completor.vim' " or whichever you use
endif
if has('nvim')
Plug 'Shougo/deoplete.nvim', { 'do': ':UpdateRemotePlugins' }
Plug 'zchee/deoplete-go', {'build': {'unix': 'make'}}
Plug 'jodosha/vim-godebug' " Debugger integration via delve
endif
" All of your Plugs must be added before the following line
call plug#end()

I also have some tmux-related plugins. See my vimrc for more details.

Once you’ve set up your plugins, run :PlugInstall and then :GoInstallBinaries to get going.

Managing differences between vim & nvim

There’s just one neovim-specific config item I needed to do to make vim and neovim work off the same configs. For some reason neovim barfs on set term=xterm-256color. ¯\_(ツ)_/¯. No worries, just if !has('nvim') it.

set t_Co=256 " ignored by neovim
let g:deoplete#enable_at_startup = 1 " ignored by vim because deoplete not installed there
if !has('nvim')
set term=xterm-256color
endif
if has('nvim')
" I have some mappings here for terminal-related stuff
endif

Deoplete

Deoplete by Shougo Matsu, (with deoplete-go), is great. Having struggled on-and-off with vim completion in the past, it’s a breath of fresh air. You’ll need to install a thing first.

Completion is the main reason I use neovim. None of the vim offerings have quite worked for me. I may be doing something wrong with the others, but now that I have something which works well I don’t care too much:

  • YCM and Neocomplete (both pre-date vim8) work synchronously, and can slow vim down at times — urrgh. Please let me know if that changes or PEBKAC.
  • Completor is an async plugin for vim8. It seems great except that completor-go was just buggy for me, it kept spewing nasty error messages each keystroke. I tried it a few months ago and quickly went back to neovim. Recently a colleague tried and had similar problems.
  • deoplete just works beautifully and super fast.

So, it’s just working for me. I’d like to hear if you’ve had better experiences with the other completers, but please also try deoplete to compare.

NOTE: with go completion and other gocode analysis tools, it’s important to regularly go install your packages. This makes it quick for gocode to analyse bytecode rather than recompiling all your packages each invocation. I just run :GoInstall occasionally. It keeps thing quick and fresh.

Similarly, go test -i keeps your code->test cycles nice and quick.

vim-godebug

vim-godebug, by Luca Guidi is a simple integration with the delve debugger by Derek Parker. It provides a way to specify a breakpoint, to start the debugger, and then drops you into a delve window for your debugging session.

Note that you need to install delve first. On mac I recommend brew install delve (homebrew sets up fiddly osx certificates for you), and on Linux you can just go get github.com/derekparker/delve/cmd/dlv

Now you can use :GoToggleBreapoint and :GoDebug to start debugging. Once the debugger fires up, you’ll need to get to grips with the debugger itself — delve commands, such as help, step, stepout, continue, print, locals, goroutines, …

This is the first time I’ve used a debugger in vim / neovim, so I’m all ‘wow’. It’s basic but it works well. FWIW the developer has indicated that he found it easier to work with neovim than vim8’s async API. I asked Luca Guidi if this plugin might become part of vim-go itself, but he and Fatih Arslan confirmed that as things stand, this won’t happen — vim-go only includes plugins compatible with vim itself. So, that’s what led me to write this article. Hope you enjoyed it.

Finally — my vimrc

It’s not the tidiest, but here it is. Copy, modify, critique, share, whatever. Cheers.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.