Using Language Servers in Neovim
Adding IDE-like features into NeoVim via the Language Server Protocol
Note: A lot has changed since the writing of this post, and I’ve changed my config to use coc.nvim. I’ve preserved the instructions as written in 2017, but you should find the latest instructions for one of the many LSP options for vim.
It’s been fascinating to watch how Microsoft has changed it’s outlook on open source now that they’re no longer the crushingly dominant force they used to be (I caught the tail end of that phase while I worked there in the early 2000s). Last summer, the team behind Visual Studio Code introduced the Language Server Protocol, which is used to power syntax highlighting, code completion, and other advanced editing features in Visual Studio. What’s exciting about the Language Server Protocol (LSP) is that it is editor neutral, so it’s not limited to a single editor.
As an ancient neckbeard, this is exciting since I use an offshoot of an editor is older than I am. Although NeoVim does many things well, IDE-like features such as code completion have always been kludgey hacks that compare poorly to GUI environments like Visual Studio. There is an effort to add support to mainline NeoVim, but integrating LSP into NeoVim today is still a bit tricky, so I decided to document the process so others don’t have to go through the same pain I did.
First, some caveats:
- I’m using NeoVim. If you use plain Vim, these instructions may or may not work for you.
- You should use a plugin manager for NeoVim, I use vim-plug, but the syntax is similar across the alternatives (the LanguageClient-neovim installation instructions may be of use for you).
- I’m assuming basic knowledge of NeoVim and the command line. If you’re comfortable in the terminal, you’re probably pretty bored by now anyway.
Now we create a minimal configuration file, which you should save to
:PlugInstall to install the plugins) you’ll see … nothing special. However, if you invoke omni completion (via
<C-x><C-u>), you’ll see the completion is much more intelligent than the default:
Other than smarter omni completion, this minimal setup also provides an error marker in the gutter indicating invalid syntax. These are both pretty nice, but really only scratch the surface of what we can do here. There is almost nothing is enabled by default, so let’s setup a few convenience mappings by adding the following to then end of
Now we can use the Language Server to find object definitions, types, and intelligently rename things. The rename is my personal favorite, since it is smarter than a normal find and replace, and respects variable scope:
This is pretty awesome, but so far it’s not much different than what was possible with other plugins like Tern for Vim. One of the exciting things about the Language Server Protocol is that it’s language agnostic. There are already implementation for several programming languages, and we get to leverage the same configuration once we’ve got our initial setup.
If I get tricked into coding python again, I can add support into NeoVim by installing the Python Language Server (via
pip install python-language-server), and adding the following to
let g:LanguageClient_serverCommands.python = ['pyls'] " Map renaming in python autocmd FileType python nnoremap <buffer> \ <leader>lr :call LanguageClient_textDocument_rename()<cr>
LanguageClient-neovim is a pretty awesome plugin, there are a two integrations that are worth setting up:
- Fuzzy finding symbols via FZF
- IDE-like completion via nvim-completion-manager
Adding this to your
init.vim is pretty easy:
Using fuzzy find to search through symbols is especially nice when some idiot decides it’s a good idea to have thousands of lines of code in a single file:
If you’re curious, I keep all my configuration files on GitHub. Let me know if you come up with any improvements!