Neovim LSP Enhanced

Additional features to enhance your LSP experience in Neovim.

Neovim — Enhanced LSP Experience

Overview

In the previous article, I walked through with you how to set up LSP and DAP in Neovim. In this article let’s enhance the LSP experience in Neovim by configuring and setting up additional features.

Installation of Language Servers

Just like the previous article, let’s get started by installing the language servers.

If you are using coc.nvim, normally the language server is installed automatically for you. For Neovim LSP, there are available plugins to automate this process. Here I will go through the manual installation steps.

Python

For Python, let’s install pyright.

$ npm install -g pyright

Golang

For Golang, let’s install gopls.

$ GO111MODULE=on go get golang.org/x/tools/gopls@latest

Rust

For Rust, let’s use rust_analyzer. The easiest way to install is to download the binary, copy it to a folder, and add the folder to the environment PATH.

Typescript

For Typescript, let’s install typescript-language-server.

$ npm install -g typescript-language-server

AutoCompletion

In the previous article, I use completion-nvim. For this article, I am going to use nvim-compe and add additional features.

In lua/plugins.lua, add the lines below to install the plugins.

use { 'neovim/nvim-lspconfig' }
use { 'hrsh7th/nvim-compe' }

Run :luafile % and :PackerInstall to install the plugins.

Create a lang folder under lua and add an init.lua file with the following content. This file sets up LSP for Python, Golang, Rust, and Typescript and also the key mappings.

init.lua

Make sure you require the file in the main init.lua

-- LSP
require('lang')

If you are not familiar with Lua-based configuration, refer to this article.

Now create a file called compe.lua under lua/config folder with the following content to configure nvim-compe.

compe.lua

In lua/config/init.lua, require compe.lua.

-- nvim-compe
require('config.compe')

Now restart Neovim and LSP should work for Python, Golang, Rust, and Typescript. Below is a sample screenshot for Golang.

Golang LSP

Auto Import

Auto import is supported. For auto import to work properly, create a file called compe.vim under plugin folder with the following content.

inoremap <silent><expr> <C-Space> compe#complete()
inoremap <silent><expr> <CR> compe#confirm('<CR>')
inoremap <silent><expr> <C-e> compe#close('<C-e>')
inoremap <silent><expr> <C-f> compe#scroll({ 'delta': +4 })
inoremap <silent><expr> <C-d> compe#scroll({ 'delta': -4 })
Javascript/Typescript — Auto Import

Calculation Completion

Calculation Completion

Spell Completion

Spell Completion based on File Type

Snippets

In the previous article, I configured completion-nvim with UltiSnips. If you need a pure Lua-based snippets plugin you can use snippets-nvim.

For nvim-compe, it supports vim-snip and snippets-nvim. I am going to use vim-snip as it supports the Visual Studio Code snippet format, and I can use existing snippets plugins available in the VSCode marketplace.

In lua/plugins.lua, add the lines below to install vim-snip and some existing code snippets. You can find out more ready snippets from the VSCode marketplace.

use { 'hrsh7th/vim-vsnip' }
use { 'cstrap/python-snippets' }
use { 'ylcnfrht/vscode-python-snippet-pack' }
use { 'xabikos/vscode-javascript' }
use { 'golang/vscode-go' }
use { 'rust-lang/vscode-rust' }

Run :luafile % and :PackerInstall to install the plugins.

Javascript Snippets
Python Code Snippets
Golang Code Snippets
Rust Code Snippets

Database AutoCompletion

In my previous article, I walked through with you how to set up vim-dadbod and vim-dadbod-ui to manage multiple databases within Vim/Neovim. Now lets set up database auto-completion using vim-dadbod-completion.

In lua/plugins.lua, add the line to install the plugin.

use { 'kristijanhusak/vim-dadbod-completion' }

Run :luafile % and :PackerInstall to install the plugin.

In existing lua/config/db.vim, add the following line.

autocmd FileType sql setlocal omnifunc=vim_dadbod_completion#omni

In lua/config/compe.lua, add the line for vim-dadbod-completion auto-completion.

max_menu_width = 100;
documentation = true;
source = {
path = true;
buffer = true;
calc = true;
vsnip = true;
nvim_lsp = true;
nvim_lua = true;
spell = true;
tags = true;
snippets_nvim = true;
treesitter = true;
vim_dadbod_completion = true;
};
vim-dadbod-completion

Code Formatting

The language servers may not have a code formatting feature by default. We can definitely hack the LSP configuration to make the formatting works by combining LSP and efm-langserver. However, I find it easier just to use Neoformat.

In lua/plugins.lua, install the plugin by adding the following line.

use { 'sbdchd/neoformat' }

Run :luafile % and :PackerInstall to install the plugin.

Taking the Lua file as an example, I need to install the Lua formatter using LuaRocks.

luarocks install --server=https://luarocks.org/dev luaformatter

Then I can run :Neoformat to format Lua files. You can map the command to a short-cut key or use an auto command to auto-format the files.

For other languages like Python, Rust, Golang, Typescript, etc, install the formatter you prefer and it should work accordingly.

lspsaga.nvim

lspsaga.nvim is a light-weight LSP plugin with a highly performant UI.

In lua/plugins.lua, install the plugin by adding the following line.

use { 'glepnir/lspsaga.nvim' }

Run :luafile % and :PackerInstall to install the plugin.

Create a file called saga.vim under plugin folder with the following mappings.

lua << EOFlocal saga = require 'lspsaga'
saga.init_lsp_saga()
EOFnnoremap <silent><leader>clf :Lspsaga lsp_finder<CR>
nnoremap <silent><leader>cca :Lspsaga code_action<CR>
vnoremap <silent><leader>cca :<C-U>Lspsaga range_code_action<CR>
nnoremap <silent><leader>chd :Lspsaga hover_doc<CR>
nnoremap <silent><C-f> <cmd>lua require('lspsaga.action').smart_scroll_with_saga(1)<CR>
nnoremap <silent><C-b> <cmd>lua require('lspsaga.action').smart_scroll_with_saga(-1)<CR>
nnoremap <silent><leader>csh :Lspsaga signature_help<CR>nnoremap <silent><leader>crn :Lspsaga rename<CR>nnoremap <silent><leader>cpd:Lspsaga preview_definition<CR>nnoremap <silent> <leader>cld :Lspsaga show_line_diagnostics<CR>nnoremap <silent> [e :Lspsaga diagnostic_jump_next<CR>
nnoremap <silent> ]e :Lspsaga diagnostic_jump_prev<CR>
nnoremap <silent> <leader>cot :Lspsaga open_floaterm<CR>
tnoremap <silent> <leader>cct <C-\><C-n>:Lspsaga close_floaterm<CR>
lspsaga.nvim LSP Finder
lspsaga.nvim Code Action

lspkind-nvim

lspkind-nvim adds VSCode-like pictograms to Neovim's built-in LSP.

In lua/plugins.lua, install the plugin by adding the following line.

use { 'onsails/lspkind-nvim' }

Run :luafile % and :PackerInstall to install the plugin.

Create a file called lspkind.lua under lua/config folder.

require('lspkind').init()

Require lspkind.lua in lua/config/init.lua

-- lspkind-nvim
require('config.lspkind')

And in your LSP menu, you should see the icons.

lsp-kind.nvim

vim-illuminate

Let’s install vim-illuminate to automatically highlighting other uses of the current word under the cursor.

In lua/plugins.lua, install the plugin by adding the following line.

use { 'RRethy/vim-illuminate' }

Run :luafile % and :PackerInstall to install the plugin.

In lua/lang/init.lua, add the following line to attach it to the language server.

local on_attach = function(client, bufnr)
require 'illuminate'.on_attach(client)

Restart Neovim and you should see the highlighting now.

vim-illuminate

vim-which-key

I defined many keys mappings. Let’s install vim-which-key to make it easier to know the available key bindings.

In lua/plugins.lua, install the plugin by adding the following line.

use { 'liuchengxu/vim-which-key' }

Run :luafile % and :PackerInstall to install the plugin.

Create a file called whichkey.vim under plugin folder with the following mappings.

nnoremap <silent> <leader>      :<c-u>WhichKey '<leader>'<CR>
vnoremap <silent> <leader> :silent <c-u> :silent WhichKeyVisual '<leader>'<CR>

Restart Neovim and now whenever I press the Leader key I should be able to see the available key bindings.

vim-which-key

nvim-ts-rainbow

Let’s install rainbow parentheses for Neovim using nvim-ts-rainbow.

In lua/plugins.lua, install the plugin by adding the following line.

use { 'p00f/nvim-ts-rainbow' }

Run :luafile % and :PackerInstall to install the plugin.

In lua/config/treesitter.lua add the following lines as part of treesitter setup.

rainbow = {
enable = true
}

Restart Neovim and you should see it take effect.

nvim-ts-rainbow

Summary

The Neovim ecosystem is evolving fast and there are new features and plugins coming up from time to time. It is definitely fun hacking it.

The dotfiles I used can be found in this repository.

Do check out these articles!

References

Programmer and occasional blogger.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store