{"id":2087,"date":"2022-06-12T03:35:17","date_gmt":"2022-06-11T22:05:17","guid":{"rendered":"https:\/\/smarttech101.com\/?p=2087"},"modified":"2023-08-25T17:33:03","modified_gmt":"2023-08-25T12:03:03","slug":"nvim-lsp-configure-language-servers-shortcuts-highlights","status":"publish","type":"post","link":"https:\/\/smarttech101.com\/nvim-lsp-configure-language-servers-shortcuts-highlights\/","title":{"rendered":"Nvim lsp: configure language servers, shortcuts, highlights"},"content":{"rendered":"\n
Nvim LSP (Neovim Language Server Protocol) enables you to code efficiently by predicting what you are going to type, early diagnosis, etc. In this article, I will explain what is LSP, what are language servers, how to configure them in nvim, highlight symbols under the cursor, keybindings for code actions, rename, hover info, implementations, definition and declaration, workspace, and many more.<\/p>\n\n\n\n
If have not set up basic configuration in Neovim, do that over here<\/a>. This article is part of my series on setting up Nvim Lsp (Neovim Language Server Protocol):<\/p>\n\n\n\n I recommend you to follow all three articles in the above order.<\/p>\n\n\n\n Language Servers<\/strong>, like any other servers, run in the background of your computer and they serve their services such as autocompletion, diagnostics (linting), formatting, hover information, renaming, etc. to any ‘client<\/strong>‘ such as neovim<\/strong>\/vscode\/atom\/sublime. These services are served by following a special communication protocol called Language Server Protocol<\/a>.<\/p>\n\n\n\n LSP is a rather new protocol and most modern editors are starting to support this. As of 10 June 2022, Vim still does not support this natively. You need to install special plugins in vim for this feature. But neovim, starting from version 0.5<\/strong>, has started to support this in its core version itself (use the command For each famous programming language, we have at least one language server. For example, Before language servers came into existence, each editor needed to provide dedicated support for each language in its own unique way. It was a cumbersome process. But now, language developers only need to develop the language and the corresponding server. And editors supporting LSP can connect with these servers without having any dedicated support for the language itself.<\/p>\n\n\n\n Use your favorite plug-in managers to install these plug-ins:<\/p>\n\n\n\n In this article, I will explain everything using the There are many ways to install the servers:<\/p>\n\n\n\n Arch Linux:<\/p>\n\n\n\n Other distributions\/OSes:<\/p>\n\n\n\n After installing the servers, you need to set up Key Bindings and Highlights and then server configurations.<\/p>\n\n\n\n First, you need to create a file In the file Where, <\/p>\n\n\n\n Now, I will help you populate your Symbols are special keywords in your code such as variables, functions, etc. To get a list of the symbols, execute the command To bind the command with the key Definition<\/strong>: When you put your cursor on any ‘symbol’ and execute the vim command Declaration<\/strong> ( To bind the above definition and declaration command with the keys Hover information gives you a help document in a floating window when you ‘hover’ your cursor on any special keyword. For example, in bash language, hovering on To bind the hover command Please note that “hovering” in neovim is slightly different. Here, you first need to put your cursor instead of just hover on the symbol and then press Executing the neovim command However, if your language server does not support this you might see the message To bind this command with the key Signature help shows information about the parameters of your function\/method in a floating window. For example, suppose you have defined a function with a list of parameters (or variables). When you start to type the parameters’ values one after another, some helpful information will be shown in a floating window.<\/p>\n\n\n\n To bind the signature help command However, personally, I find it less useful than using another plug-in A “workspace<\/strong>” is the collection of one or more folders that are opened in your window (source: Workspace in vscode<\/a>).<\/p>\n\n\n\n To have keybindings for add, remove, and list workspaces, use the following code in your The command To bind this command with the key When you write your projects, you might encounter errors\/warnings. Code actions in that case are available suggestions to fix\/remove these errors and warnings. Not all language servers provide this service.<\/p>\n\n\n\n To bind the key Now press Sometimes, code actions are available even if there is no error\/warning\/information\/hint. In that case, you can show a lightbulb using Nvim lsp command To bind this command with Formatting removes\/enters unnecessary spaces, newline characters, etc., and thus makes your code look soothing to the eyes.<\/p>\n\n\n\n To bind the formatting command However, only a few language servers (ex – lua-language-server) provide formatting but others (ex – bash-language-server) don’t. So, use a plug-in called null-ls which kind of merges formatters with language servers. For example, bash-language-server does not provide formatting. Therefore by using Note 1:<\/strong> Please note that the formatting command is a little different in nvim v 0.8:<\/p>\n\n\n\n The neovim command To bind this command with the key When you put your cursor on any one symbol, the symbol is highlighted everywhere.<\/p>\n\n\n\n To highlight the symbol under the cursor, put the following code in the same file As you can see I am using the Edit 15\/11\/2022: For Neovim 0.8 or above, use \ud83d\udcd3Note<\/strong>: You can change the \n
Table of Contents<\/h2>\n\n\n\n
\n
\n
\n
What are Language Server and LSP<\/h2>\n\n\n\n
nvim --version<\/code> to find your version of neovim). You don’t have to install any plugin in neovim for this. At the same time, there are some related plug-ins in neovim which makes configuring and using language servers easy. I will be recommending such plug-ins in the upcoming paras.<\/p>\n\n\n\n
bash-language-server<\/code> (sometimes also called
bashls<\/code>) is for
bash<\/code> language,
pyright<\/code> is for
python<\/code> language,
lua-language-server<\/code> (also known as
sumneko_lua<\/code>) for
lua<\/code> language.<\/p>\n\n\n\n
Install useful plug-ins for nvim lsp<\/h2>\n\n\n\n
\n
neovim\/nvim-lspconfig<\/code><\/li>\n\n\n\n
hrsh7th\/nvim-cmp<\/code> provides additional completion capabilities.<\/li>\n<\/ul>\n\n\n\n
Install necessary language servers<\/h2>\n\n\n\n
lua-language-server<\/code>,
pyright<\/code> (
python-language-server<\/code>) and
bash-language-server<\/code>. For others, the procedure is exactly similar. To get a list of available servers, visit the neovim site for server configuration<\/a>.<\/p>\n\n\n\n
\n
apt<\/code> for Debian,
pacman<\/code> for Arch Linux). This is best<\/strong> of all because now, the packages will be upgraded by your package managers and you don’t have to do that manually.<\/li>\n\n\n\n
pacman -S bash-language-server lua-language-server pyright<\/code><\/pre>\n\n\n\n
pip install pyright\nnpm i -g bash-language-server\nbrew install lua-language-server\nport install lua-language-server<\/code><\/pre>\n\n\n\n
Set up key bindings in neovim-lsp<\/h2>\n\n\n\n
~\/.config\/nvim\/plug-config\/lspconfig.lua<\/code>. Now, you need to populate it with configuration. In the very end, I will show you how to ‘source’ it in your
init.vim<\/code>. Only after that, you will see any result.<\/p>\n\n\n\n
~\/.config\/nvim\/plug-config\/lspconfig.lua<\/code>, first, create an
on_attach<\/code> function, then put your keybindings into it:<\/p>\n\n\n\n
local on_attach = function(client, bufnr)\n local opts = { noremap = true, silent = true }\n KEY_BINDING_1\n KEY_BINDING_2\nend<\/code><\/pre>\n\n\n\n
\n
opt<\/code> variable will be used in setting up your keybindings.<\/li>\n\n\n\n
on_attach<\/code> function makes sure that these <\/strong>key-bindings are only created when there is any Language Server attached to the neovim. In our example, we will be configuring the servers only for lua, bash, and python. So, when you open any file with filetypes other than lua, bash and python, these key-bindings will not take any action.<\/li>\n\n\n\n
:help nvim_buf_set_keymap()<\/code> for more information.<\/li>\n<\/ul>\n\n\n\n
on_attach<\/code> function with the necessary key bindings.<\/p>\n\n\n\n
Symbols in nvim-lsp<\/h3>\n\n\n\n
:lua vim.lsp.buf.document_symbol()<\/code>.<\/p>\n\n\n\n
<leader>ls<\/code>, put the following code inside your
on_attach<\/code> function:<\/p>\n\n\n\n
vim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>ls', '<cmd>lua vim.lsp.buf.document_symbol()<CR>', opts)<\/code><\/pre>\n\n\n\n
Definition and Declaration in nvim lsp<\/h3>\n\n\n\n
lua vim.lsp.buf.definition()<\/code>, your cursor will move to the definition of the symbol. This is quite handy for big projects spread over a large number of files and lines.<\/p>\n\n\n\n
:lua vim.lsp.buf.declaration()<\/code>): many servers do not support the Declaration. Most of the time, Definition is enough.<\/p>\n\n\n\n
<leader>ld<\/code> and
<leader>lD<\/code>, put the following code inside your
on_attach<\/code> function:<\/p>\n\n\n\n
vim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>lD', '<cmd>lua vim.lsp.buf.declaration()<CR>', opts)\nvim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>ld', '<cmd>lua vim.lsp.buf.definition()<CR>', opts)<\/code><\/pre>\n\n\n\n
Hover information in nvim lsp<\/h3>\n\n\n\n
find<\/code> command will give you find’s man page, in python language, hovering on
print()<\/code> will give you short information about the print function.<\/p>\n\n\n\n
path<\/code>) and execute the hover command to get the hover information.<\/figcaption><\/figure>\n\n\n\n
:lua vim.lsp.buf.hover()<\/code> with the key
<leader>lk<\/code>, put the following code in your
on_attach<\/code> function:<\/p>\n\n\n\n
vim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>lk', '<cmd>lua vim.lsp.buf.hover()<CR>', opts)<\/code><\/pre>\n\n\n\n
<leader>lk<\/code>. Press this shortcut key again and you will reach into the floating ‘window’. To get out of the floating window, quit (
:q<\/code>) as usual.<\/p>\n\n\n\n
Implementation in nvim lsp<\/h3>\n\n\n\n
:lua vim.lsp.buf.implementation()<\/code> on any symbol will list all the implementations<\/strong> for the symbol under the cursor in the quickfix window. <\/p>\n\n\n\n
method textDocument\/implementation is not supported by any of the servers registered for the current buffer<\/code> at the bottom of your neovim. For your information, the bash-language-server, lua-language-server, and pyright do not support implementations<\/a>.<\/p>\n\n\n\n
<leader>lI<\/code>, put the following code in your
attach_function<\/code>:<\/p>\n\n\n\n
vim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>lI', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)<\/code><\/pre>\n\n\n\n
Signature help in nvim lsp<\/h3>\n\n\n\n
:lua vim.lsp.buf.signature_help()<\/code> with the key
<leader>lsh<\/code>, use the following code in your
on_attach<\/code> function:<\/p>\n\n\n\n
vim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>lsh', '<cmd>lua vim.lsp.buf.signature_help()<CR>', opts)<\/code><\/pre>\n\n\n\n
hrsh7th\/cmp-nvim-lsp-signature-help<\/code>. The plug-in gives the signature-help in the floating window without using any shortcut key. On top of that, the plug-in also boaldens the variable under consideration (in figure 2,
var2<\/code> is shown in bold in the floating window as I am about to write its value). I will cover more about signature-help in the next article on nvim-lsp autocompletion<\/a>.<\/p>\n\n\n\n
Workspace in nvim lsp<\/h3>\n\n\n\n
on_attach<\/code> function:<\/p>\n\n\n\n
vim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>lwa', '<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>', opts)\nvim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>lwr', '<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>', opts)\nvim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>lwl', '<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>', opts)<\/code><\/pre>\n\n\n\n
Rename symbols in nvim lsp<\/h3>\n\n\n\n
:lua vim.lsp.buf.rename()<\/code> only renames<\/strong> all references to the symbol under the cursor. It does not rename the string in other places such as comments.<\/p>\n\n\n\n
<leader>lr<\/code>, put the following code in your
on_attach<\/code> function:<\/p>\n\n\n\n
vim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>lr', '<cmd>lua vim.lsp.buf.rename()<CR>', opts)<\/code><\/pre>\n\n\n\n
Code actions in nvim lsp<\/h3>\n\n\n\n
<leader>lc<\/code> with the command
:lua vim.lsp.buf.code_action()<\/code>, use the following code in your
on_attach<\/code> function:<\/p>\n\n\n\n
vim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>lc', '<cmd>lua vim.lsp.buf.code_action()<CR>', opts)<\/code><\/pre>\n\n\n\n
<leader>lc<\/code> on any symbol\/line with an error\/warning, it would show you possible code actions<\/strong> (like how to solve\/remove the error\/warning) you can do. It gives a list of actions in command line mode and you have to enter a number to choose the action.<\/p>\n\n\n\n
kosayoda\/nvim-lightbulb<\/code> plug-in.<\/p>\n\n\n\n
List all references to the symbol using nvim lsp<\/h3>\n\n\n\n
:lua vim.lsp.buf.references()<\/code> on any symbol under the cursor lists all the references<\/strong> to the symbol in a quickfix window.<\/p>\n\n\n\n
filename<\/code> in the quickfix window shown in red.<\/figcaption><\/figure>\n\n\n\n
<leader>lR<\/code>, put the following code in your
on_attach<\/code> function:<\/p>\n\n\n\n
vim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>lR', '<cmd>lua vim.lsp.buf.references()<CR>', opts)<\/code><\/pre>\n\n\n\n
Formatting in nvim lsp<\/h3>\n\n\n\n
:lua vim.lsp.buf.formatting()<\/code> with the key
<leader>lf<\/code>, use the following code in your
on_attach<\/code> function:<\/p>\n\n\n\n
vim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>lf', '<cmd>lua vim.lsp.buf.formatting()<CR>', opts)<\/code><\/pre>\n\n\n\n
null-ls<\/code>, you can “bring” the formatting ability into this from a separate formatter shfmt<\/a>. To use it, head over to my in-depth article on null-ls<\/a>.<\/p>\n\n\n\n
-- 0.7\nvim.lsp.buf.formatting_sync(nil, 2000) -- 2 seconds\n\n-- 0.8\nvim.lsp.buf.format({ timeout_ms = 2000 }) -- 2 seconds<\/code><\/pre>\n\n\n\n
Get information about language servers attached to neovim<\/h3>\n\n\n\n
LspInfo<\/code> prints detected filetype, attached language servers, root directory, etc. in a floating window.<\/p>\n\n\n\n
<leader>li<\/code>, put the following code in your
on_attach<\/code> function:<\/p>\n\n\n\n
vim.api.nvim_buf_set_keymap(bufnr, 'n', '<leader>li', '<cmd>LspInfo<CR>', opts)<\/code><\/pre>\n\n\n\n
Highlight symbol under the cursor using nvim lsp<\/h2>\n\n\n\n
filename<\/code> under the cursor<\/figcaption><\/figure>\n\n\n\n
~\/.config\/nvim\/plug-config\/lspconfig.lua<\/code>. Please note that these lines should go into the
on_attach<\/code> function.<\/strong><\/p>\n\n\n\n
if client.resolved_capabilities.document_highlight then\n vim.cmd [[\n hi! LspReferenceRead cterm=bold ctermbg=235 guibg=LightYellow\n hi! LspReferenceText cterm=bold ctermbg=235 guibg=LightYellow\n hi! LspReferenceWrite cterm=bold ctermbg=235 guibg=LightYellow\n ]]\n vim.api.nvim_create_augroup('lsp_document_highlight', {})\n vim.api.nvim_create_autocmd({ 'CursorHold', 'CursorHoldI' }, {\n group = 'lsp_document_highlight',\n buffer = 0,\n callback = vim.lsp.buf.document_highlight,\n })\n vim.api.nvim_create_autocmd('CursorMoved', {\n group = 'lsp_document_highlight',\n buffer = 0,\n callback = vim.lsp.buf.clear_references,\n })\n end<\/code><\/pre>\n\n\n\n
if..end<\/code> condition for highlighting. This prevents neovim from asking the language server to highlight your symbol if the server does not have this ability.<\/p>\n\n\n\n
client.server_capabilities.documentHighlightProvider<\/code><\/strong> instead of
client.resolved_capabilities.document_highlight<\/code><\/strong>.<\/p>\n\n\n\n
ctermbg<\/code> and\/or
guibg<\/code> to get the appropriate highlighting color. Similarly, you can also use italics instead of bold, provided your terminal supports it.<\/p>\n\n\n\n