After having used YouCompleteMe, I finally decided to give one of the Language Server Protocol (LSP) implementations a spin. As an LLVM developer I’ve been following clangd’s development and wanted to try it out.
At the time of writing, several LSP implementations exist for Vim:
Setting up vim-lsp
I decided to go with vim-lsp because it’s asyncronous, written in vimscript and easy to setup. The plugin has a single dependency: async.vim which provides an abstraction layer between async job control in vim8 and neovim. If you’re using vim-plug to manage your plugins, you just need to add the following two entries to your .vimrc
:
Plug 'prabirshrestha/async.vim'
Plug 'prabirshrestha/vim-lsp'
Auto-complete
Like many people, my motivation for having language support is having sensible auto-completion. There are several (asynchronous) plugins available that help with this, but for me Vim’s built-in omni-completion is more than sufficient. I do like having the menu show up when pressing TAB, for which I use VimCompletesMe.
Plug 'ajh17/vimcompletesme'
See the section below on how to hook up vim-lsp with omni-completion.
Other LSP features
The language server protocol has several features, but some server and client implmenetations only support part of the commands. Below is a table of features supported by the protocol, clangd and the vim-lsp plugin.
Editor feature | lsp | clangd | vim-lsp |
---|---|---|---|
Formatting | Yes | Yes | Yes |
Completion | Yes | Yes | Yes |
Diagnostics | Yes | Yes | Yes |
Fix-its | Yes | Yes | Yes |
Go to Definition | Yes | Yes | Yes |
Signature Help | Yes | Yes | No |
Document Highlights | Yes | Yes | No |
Rename | Yes | Yes | Yes |
Source hover | Yes | Yes | Yes |
Find References | Yes | No | Yes |
Code Lens | Yes | No | No |
Document Symbols | Yes | No | Yes |
Workspace Symbols | Yes | No | Yes |
For an up-to-date status on the different features, please refer to the clangd and vim-lsp documentation:
Configure vim to use clangd
Finally, below is the configuration for hooking up clangd with vim-lsp. If the clangd
binary exists, we register the LSP server and tell vim to use it for omni-completion.
if executable('clangd')
augroup lsp_clangd
autocmd!
autocmd User lsp_setup call lsp#register_server({
\ 'name': 'clangd',
\ 'cmd': {server_info->['clangd']},
\ 'whitelist': ['c', 'cpp', 'objc', 'objcpp'],
\ })
autocmd FileType c setlocal omnifunc=lsp#complete
autocmd FileType cpp setlocal omnifunc=lsp#complete
autocmd FileType objc setlocal omnifunc=lsp#complete
autocmd FileType objcpp setlocal omnifunc=lsp#complete
augroup end
endif
JSON Compilation Database
Like many tools, clangd
relies on the presence of a JSON compilation database. This file is usually called compile_commands.json
and lives in the build directory. By default, clangd
will look for this file in the current directory and parent paths of each source file. Depending on the layout of your project, you might have to symlink it to the parent path of your current working directory, but in most cases it will just work out of the box.