Getting started with neovim's native LSP client: The easy way (2024)

A lot has changed since I wrote this post back in 2022. Back then Neovim v0.6 was the stable version and having a setup with "sane defaults" was not easy. Now, Neovim v0.10 is the current stable version and this brings a lot features that make our lives easier.

Quick note: if you don't know how to configure Neovim using lua I recommend reading this Build your first Neovim configuration in lua.

Here I'm going to show a minimal configuration for Neovim's LSP client. This is what we'll do:

  • Install a language server
  • Configure the language server
  • Setup some keymaps
  • Setup an autocompletion plugin

I'm going to show the setup for golang and rust. Why those languages? Because I assume they work well on windows, mac and linux. And I need at least two language servers to make it clear some instructions vary depending on the programming language you want to use.

We need a language server

A language server is an external program. It can analyze the source code of our projects and provide useful information to the editor. You can watch this 5 minute video if you want to know more details.

Where can we find these language servers? In the Neovim ecosystem we have a wonderful plugin called nvim-lspconfig. In the documentation of this plugin you can find a list of language servers.

Let's go to our specific examples:

If you have the toolchain for golang you can install its language server (gopls) using this command.

go install golang.org/x/tools/gopls@latest

For rust, if you have rustup installed, you can download the language server (rust_analyzer) using this command.

rustup component add rust-analyzer

Can we automate this step?

Yes. There is a plugin called mason.nvim. This will offer an interface you can use to download language servers from inside Neovim.

I will not show you how to use mason.nvim here, because it's optional. I don't want people to think mason.nvim is essential to configure Neovim. It works great, but you should understand its benefits and problems before you decide to use it.

Configure a language server

nvim-lspconfig is the plugin we will use to configure our language servers.

In our Neovim configuration we are going to add the setup function for the language servers we have installed.

We are going to follow this syntax.

require('lspconfig').example_server.setup({})

Where example_server is the name of the language server we have installed. For example:

require('lspconfig').gopls.setup({})require('lspconfig').rust_analyzer.setup({})

This is already enough to get some features working. With gopls and rust_analyzer provide error detection out the box.

Remember to read nvim-lspconfig documentation to know what language servers are supported: doc/server_configurations.md.

Custom keymaps

There are other cool features we could use now, but they are opt-in. You need to create a custom keybinding for them to work.

The common convention here is to enable these features only when a language server is active in the file we are editing. For this we use an autocommand in the event LspAttach. Like this.

-- Create the lsp keymaps only when a -- language server is activevim.api.nvim_create_autocmd('LspAttach', { desc = 'LSP actions', callback = function(event) local opts = {buffer = event.buf} vim.keymap.set('n', 'K', '<cmd>lua vim.lsp.buf.hover()<cr>', opts) vim.keymap.set('n', 'gd', '<cmd>lua vim.lsp.buf.definition()<cr>', opts) vim.keymap.set('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<cr>', opts) vim.keymap.set('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<cr>', opts) vim.keymap.set('n', 'go', '<cmd>lua vim.lsp.buf.type_definition()<cr>', opts) vim.keymap.set('n', 'gr', '<cmd>lua vim.lsp.buf.references()<cr>', opts) vim.keymap.set('n', 'gs', '<cmd>lua vim.lsp.buf.signature_help()<cr>', opts) vim.keymap.set('n', '<F2>', '<cmd>lua vim.lsp.buf.rename()<cr>', opts) vim.keymap.set({'n', 'x'}, '<F3>', '<cmd>lua vim.lsp.buf.format({async = true})<cr>', opts) vim.keymap.set('n', '<F4>', '<cmd>lua vim.lsp.buf.code_action()<cr>', opts) end,})

Here's the description of the keymaps:

Setup autocompletion

nvim-cmp is the plugin we will use to get code autocompletion. By default nvim-cmp only handles the interface of the completion menu. It does not gather data from language servers or any other source.

cmp_nvim_lsp is an extension for nvim-cmp. This is the plugin that collects data from the language servers and gives it to nvim-cmp.

So a minimal configuration for nvim-cmp would like this.

local cmp = require('cmp')cmp.setup({ sources = { {name = 'nvim_lsp'}, }, snippet = { expand = function(args) vim.snippet.expand(args.body) end }, mapping = cmp.mapping.preset.insert({}),})

What does this do? sources will be the list of nvim-cmp extensions that gather data.

mapping is where you add your keybindings.

snippet.expand is a function that gives the snippet text to other plugins, so they can parse it and expand it. But in this case we are using Neovim's built-in snippet engine (only available v0.10).

What about this cmp.mapping.preset.insert({}) thing? That is a set of keymaps that are meant to emulate Neovim's defaults. It will set the following keymaps:

  • <Ctrl-y>: Confirms selection.

  • <Ctrl-e>: Cancel the completion.

  • <Down>: Navigate to the next item on the list.

  • <Up>: Navigate to previous item on the list.

  • <Ctrl-n>: Go to the next item in the completion menu, or trigger completion menu.

  • <Ctrl-p>: Go to the previous item in the completion menu, or trigger completion menu.

If you want to add more keymaps, you put them inside the curly braces.

mapping = cmp.mapping.preset.insert({ -- confirm completion ['<Enter>'] = cmp.mapping.confirm({select = true}), -- scroll up and down the documentation window ['<C-u>'] = cmp.mapping.scroll_docs(-4), ['<C-d>'] = cmp.mapping.scroll_docs(4), }),

One more thing...

Now that we have cmp_nvim_lsp configured we need to update the options we send to our language servers.

So, we need to get the "default capabilities" provided by cmp_nvim_lsp and add them to the setup function of our language servers.

This is what we do:

local lsp_capabilities = require('cmp_nvim_lsp').default_capabilities()require('lspconfig').example_server.setup({ capabilities = lsp_capabilities,})

For our concrete example with go and rust it'll be like this.

local lsp_capabilities = require('cmp_nvim_lsp').default_capabilities()require('lspconfig').gopls.setup({ capabilities = lsp_capabilities,})require('lspconfig').rust_analyzer.setup({ capabilities = lsp_capabilities,})

Complete code

We are done. We have everything we need to start our journey.

Here's the complete code from the previous sections put together.

----- Autocompletion---local cmp = require('cmp')cmp.setup({ sources = { {name = 'nvim_lsp'}, }, snippet = { expand = function(args) vim.snippet.expand(args.body) end }, mapping = cmp.mapping.preset.insert({ -- confirm completion ['<Enter>'] = cmp.mapping.confirm({select = true}), -- scroll up and down the documentation window ['<C-u>'] = cmp.mapping.scroll_docs(-4), ['<C-d>'] = cmp.mapping.scroll_docs(4), }),})----- Language server configuration----- Create the lsp keymaps only when a -- language server is activevim.api.nvim_create_autocmd('LspAttach', { desc = 'LSP actions', callback = function(event) local opts = {buffer = event.buf} vim.keymap.set('n', 'K', '<cmd>lua vim.lsp.buf.hover()<cr>', opts) vim.keymap.set('n', 'gd', '<cmd>lua vim.lsp.buf.definition()<cr>', opts) vim.keymap.set('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<cr>', opts) vim.keymap.set('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<cr>', opts) vim.keymap.set('n', 'go', '<cmd>lua vim.lsp.buf.type_definition()<cr>', opts) vim.keymap.set('n', 'gr', '<cmd>lua vim.lsp.buf.references()<cr>', opts) vim.keymap.set('n', 'gs', '<cmd>lua vim.lsp.buf.signature_help()<cr>', opts) vim.keymap.set('n', '<F2>', '<cmd>lua vim.lsp.buf.rename()<cr>', opts) vim.keymap.set({'n', 'x'}, '<F3>', '<cmd>lua vim.lsp.buf.format({async = true})<cr>', opts) vim.keymap.set('n', '<F4>', '<cmd>lua vim.lsp.buf.code_action()<cr>', opts) end,})local lsp_capabilities = require('cmp_nvim_lsp').default_capabilities()-- These are just examples. Replace them with the language-- servers you have installed in your system.require('lspconfig').gopls.setup({ capabilities = lsp_capabilities,})require('lspconfig').rust_analyzer.setup({ capabilities = lsp_capabilities,})

Thank you for your time. If you find this article useful and want to support my efforts, consider leaving a tip in buy me a coffee ☕.

Getting started with neovim's native LSP client: The easy way (1)

Getting started with neovim's native LSP client: The easy way (2024)

References

Top Articles
DisableMyCable.com - A Comparison of the Best Broadcast TV Recorders (DVRs) in 2024
How to Watch USA Network Online Without Cable
Funny Roblox Id Codes 2023
Golden Abyss - Chapter 5 - Lunar_Angel
Www.paystubportal.com/7-11 Login
Joi Databas
DPhil Research - List of thesis titles
Shs Games 1V1 Lol
Evil Dead Rise Showtimes Near Massena Movieplex
Steamy Afternoon With Handsome Fernando
Which aspects are important in sales |#1 Prospection
Detroit Lions 50 50
18443168434
Newgate Honda
Zürich Stadion Letzigrund detailed interactive seating plan with seat & row numbers | Sitzplan Saalplan with Sitzplatz & Reihen Nummerierung
Grace Caroline Deepfake
978-0137606801
Nwi Arrests Lake County
Justified Official Series Trailer
London Ups Store
Committees Of Correspondence | Encyclopedia.com
Pizza Hut In Dinuba
Jinx Chapter 24: Release Date, Spoilers & Where To Read - OtakuKart
How Much You Should Be Tipping For Beauty Services - American Beauty Institute
Free Online Games on CrazyGames | Play Now!
Sizewise Stat Login
VERHUURD: Barentszstraat 12 in 'S-Gravenhage 2518 XG: Woonhuis.
Jet Ski Rental Conneaut Lake Pa
Unforeseen Drama: The Tower of Terror’s Mysterious Closure at Walt Disney World
Ups Print Store Near Me
C&T Wok Menu - Morrisville, NC Restaurant
How Taraswrld Leaks Exposed the Dark Side of TikTok Fame
University Of Michigan Paging System
Dashboard Unt
Access a Shared Resource | Computing for Arts + Sciences
Speechwire Login
Healthy Kaiserpermanente Org Sign On
Restored Republic
3473372961
Jambus - Definition, Beispiele, Merkmale, Wirkung
Ark Unlock All Skins Command
Craigslist Red Wing Mn
D3 Boards
Jail View Sumter
Nancy Pazelt Obituary
Birmingham City Schools Clever Login
Thotsbook Com
Funkin' on the Heights
Vci Classified Paducah
Www Pig11 Net
Ty Glass Sentenced
Latest Posts
Article information

Author: Madonna Wisozk

Last Updated:

Views: 6201

Rating: 4.8 / 5 (48 voted)

Reviews: 87% of readers found this page helpful

Author information

Name: Madonna Wisozk

Birthday: 2001-02-23

Address: 656 Gerhold Summit, Sidneyberg, FL 78179-2512

Phone: +6742282696652

Job: Customer Banking Liaison

Hobby: Flower arranging, Yo-yoing, Tai chi, Rowing, Macrame, Urban exploration, Knife making

Introduction: My name is Madonna Wisozk, I am a attractive, healthy, thoughtful, faithful, open, vivacious, zany person who loves writing and wants to share my knowledge and understanding with you.