A quick guide to set up nvim built in LSP

Emilien Lemaire
4 min readDec 6, 2020
nvim built in LSP at work

Edit: This article was update after the decision of the lspconfig team to delete the download option for some clients, and the moving to init.lua configuration file.

Background

In the last few months I’ve been learning how to use vim, and more specifically neovim.

As a developper one of the most useful tool we have now is the LSP. So naturally I’ve been looking forward to neovim builtin LSP. But when it came i found it really hard to find any quick guide to set it up.

So I decided to create this guide after experimenting with nvim’s LSP to help other who would like, as I did, a quick guide to set up nvim built in LSP.

Some parts of this configuration are inspired by tjdevries configuration files.

Requirements

You can install completion-nvim and nvim-lspconfig with your favorite plugin manager.

You do not need to know how to program in lua to follow this guide. It’s an easy language to understand and the api provided are pretty self documented by the names of the functions.

Setting up the LSP

The first thing you should do is to create a lua folder at the root of your neovim configuration directory. As it’s always good to keep an ordered config directory, we will put all the lua configuration files in it.

Inside your lua directory you can create the lsp_config.lua file.

You should now have a nvim configuration directory that looks like this (plus all your other nvim config files):

.
├── init.lua
└── lua
└── lsp_config.lua

It’s now time to edit your lsp_config.lua file.

First if you have installed completion-nvim as vim package, you need to add this first in your lsp_config.lua file:

vim.cmd [[ packadd completion-nvim ]]

Adding a few local variables and helper function

We are now going to add a few important variables that are going to be useful to avoid very verbose code in the next steps:

local lsp = require('lspconfig')
local completion = require('completion')

Without this variables we would have to write require('lspconfig') or require('completion') in place of lsp and completion which could get annoying very quickly.

The next step is to create an helper function to bind new mappings, this function will be useful later in the configuration.

local mapper = function(mode, key, result)
vim.api.nvim_buf_set_keymap(0, mode, key, "<cmd>lua "..result.."<cr>", {noremap = true, silent = true})
end

This function enables us to map the key to the result only in the current buffer we’re working on, the mode as the name says specify in which mode this key mapping will be enabled. Note that the mappings we’ll do with this function will override the precedent key mappings with the same key.

A custom attach function

The next thing we need is an attach function. This is where we will add all the things we want the LSP client to do when it’s attached a new buffer.

When you open a new buffer for which the language is supported by one of the LSPs you have set up, this function will be called.

local custom_attach = function()
completion.on_attach()
-- Move cursor to the next and previous diagnostic
mapper('n', '<leader>dn', 'vim.lsp.diagnostic.goto_next()')
mapper('n', '<leader>dp', 'vim.lsp.diagnostic.goto_prev()')
end

This attach function is really short, but if you wish you can add more mappings to it, and check the completion-nvim github to check other capabilities it offers.

Putting the LSP specifics mappings in this function enables them only when the LSP is working, and not in your other buffers, where they could create errors of the LSP is not working.

Adding some LSP configs

Now is the we all have been waiting for, the LSP configs. After you have set all your locals and helper/attach functions.

You should first take a look at the nvim-lspconfig readme, in the CONFIG.md file you have all the included configurations that the plugin provides.

If you want to add the pyls(make sure you have. pyls installed) as an example, you just have to add these lines to your lsp_config.lua file:

lsp.pyls.setup{
on_attach = custom_attach
}

For most of the configurations provided you only have to add these line, replacing the pyls by the LSP you wish to use. With the on_attach key, the custom_attach function will be called every time you open a new buffer that activates the LSP.

Custom lsp config

I have been using OCaml, and I found out the provided configs didn’t work well for me. Luckily you can add custom configs.

For OCamllsp (you can istall it as explained on the github page) I added this custom config:

local configs = require('lspconfig/configs')configs.ocamllsp = {
default_config = {
cmd = { 'ocamllsp' };
filtypes = {'ocaml'};
root_dir = function(fname)
return lsp.util.find_git_ancestor(fname) or vim.loop.os_homedir()
end;
settings = {};
}
}

Then to activate the config, you just have to add these lines, just as the other LSPs.

lsp.ocamllsp.setup{
on_attach = custom_attach
}

Sourcing your LSP configs

Finally in your init.lua file you just have to add this line:

require('lsp_config')

Putting it all together

You should now have an lsp_config.lua file that looks like that:

I hope you found this quick guide useful.

If you are curious about a more complete nvim configuration, you cam look at mine on github. You can find a lot of other configs on GitHub, it is always to check what the others are doing to find some inspirations and help.

You can also check my other Neovim guides:

--

--