DEV Community

Heiker
Heiker

Posted on • Edited on

Configurando el cliente LSP de neovim: la manera fácil

Mucho ha cambiado desde que escribí esta guía en el año 2022. En aquel entonces Neovim v0.6 era la versión estable más reciente e implementar "funcionalidades básicas" no era fácil. Ahora quiero mostrarles una configuración que pueden usar en Neovim v0.9 o mayor.

Importante: si no saben cómo configurar Neovim usando lua les recomiendo leer esto: Cómo crear tu primera configuración de Neovim usando lua.

Voy a enseñarles cómo usar el cliente LSP de Neovim. Esto es lo que haremos:

  • Instalar un servidor LSP
  • Configurar el servidor LSP
  • Crear atajos de teclado
  • Configurar autocompletado de código

En esta ocasión voy a mostrar dos ejemplos prácticos, vamos a configurar servidores LSP para golang y rust. ¿Por qué esos lenguajes? Porque ambos funcionan relativamente bien en Windows, Mac y Linux. Y necesito al menos 2 ejemplos para que sea evidente que algunos pasos varían dependendiendo del lenguaje de programación que quieren usar.

Necesitamos un servidor LSP

Un servidor LSP es un programa externo. Por lo general están diseñados para analizar el código fuente de un proyecto y proveer información a un editor de texto. Si quieren conocer más detalles pueden ver este video: LSP explained (5 min).

Ahora bien ¿Dónde podemos encontrar servidores LSP para Neovim?

La comunidad de Neovim ha creado el plugin nvim-lspconfig, en la documentación de este plugin podrán encontrar una lista de servidores compatibles con Neovim: nvim-lspconfig/doc/configs.md.

Vamos con nuestro primer ejemplo:

Si ya tienen instalado las herramientas de desarrollo para golang, podrán instalar el servidor LSP (gopls) ejecutando este comando en la terminal.

go install golang.org/x/tools/gopls@latest
Enter fullscreen mode Exit fullscreen mode

En el caso de rust, si tienen rustup instalado pueden usar este comando para descargar rust_analyzer.

rustup component add rust-analyzer
Enter fullscreen mode Exit fullscreen mode

¿Hay alguna forma de automatizar este paso?

Sí. Existe un plugin llamado mason.nvim. Este nos ofrece una interfaz que nos permite descargar herramientas desde Neovim.

No les enseñaré cómo usar mason.nvim aquí, porque este plugin es opcional. No quiero que nadie piense que mason.nvim es obligatorio para este proceso. Funciona genial pero antes de usarlo ustedes deben leer bien las instrucciones, y deben entender si les conviene instalarlo o no.

Configurando un servidor LSP

nvim-lspconfig es el plugin que usaremos para configurar servidores LSP.

Justo ahora (Febrero 2026) estamos en un periodo de transición. Neovim v0.11 es la versión estable actual, y aquí se ha implementado un método nuevo para configurar servidores LSP. Pero en muchos sistemas basados en Linux la versión de Neovim puede variar. En algunos casos Neovim v0.9 o v0.10 es la versión que tienen disponibles de manera oficial.

Aquí les mostraré el método antiguo para versiones anteriores a v0.11 y el método nuevo.

En Neovim v0.11 en adelante, para configurar un servidor LSP deben ejecutar la función vim.lsp.enable().

vim.lsp.enable({'example_server'})
Enter fullscreen mode Exit fullscreen mode

En Neovim v0.10 o versiones anteriores debemos usar el "framework" que se encuentra en el módulo lspconfig.

require('lspconfig').example_server.setup({})
Enter fullscreen mode Exit fullscreen mode

Importante: Las versiones más reciente de nvim-lspconfig sólo ofrecen soporte para Neovim v0.10 en adelante. Si necesitan soporte para Neovim v0.9 pueden usar el tag v1.8.0 de nvim-lspconfig.

Entonces, si tenemos disponible Neovim v0.11 podremos habilitar los servidores LSP de esta manera:

vim.lsp.enable({'gopls', 'rust_analyzer'})
Enter fullscreen mode Exit fullscreen mode

Para versiones anteriores tendríamos que hacer esto:

require('lspconfig').gopls.setup({})
require('lspconfig').rust_analyzer.setup({})
Enter fullscreen mode Exit fullscreen mode

Ya esto es suficiente para poder usar algunas funcionalidades de los servidores LSP. gopls and rust_analyzer podrán indicar si tenemos errores en nuestro código.

Si quieren que su configuración sea compatible en diferentes versiones de Neovim pueden crear una función que invoque el método correcto de acuerdo a la versión de Neovim que están usando.

-- Esta función usará el método adecuado para configurar un servidor LSP.
-- Ya que vim.lsp.enable() sólo está disponible en versiones más recientes.
local function lsp_setup(server, opts)
  if vim.fn.has('nvim-0.11') == 0 then
    require('lspconfig')[server].setup(opts)
    return
  end

  if not vim.tbl_isempty(opts) then
    vim.lsp.config(server, opts)
  end

  vim.lsp.enable(server)
end
Enter fullscreen mode Exit fullscreen mode

Y luego para habilitar un servidor LSP lo usamos de esta manera:

lsp_setup('gopls', {})
lsp_setup('rust_analyzer', {})
Enter fullscreen mode Exit fullscreen mode

Recuerden revisar la documentación de nvim-lspconfig para saber qué servidores LSP pueden usar.

Atajos de teclado

Neovim v0.11 viene con atajos de teclado predefinidos, pero si tenemos una versión anterior debemos crear esos atajos nosotros mismos. Aquí les muestro el código que pueden usar en caso de no tener acceso a Neovim v0.11.

-- Estos atajos ya están definidos en Neovim v0.10
vim.keymap.set('n', '[d', '<cmd>lua vim.diagnostic.goto_prev()<cr>')
vim.keymap.set('n', ']d', '<cmd>lua vim.diagnostic.goto_next()<cr>')
vim.keymap.set('n', '<C-w>d', '<cmd>lua vim.diagnostic.open_float()<cr>')
vim.keymap.set('n', '<C-w><C-d>', '<cmd>lua vim.diagnostic.open_float()<cr>')

vim.api.nvim_create_autocmd('LspAttach', {
  callback = function(event)
    local bufmap = function(mode, rhs, lhs)
      vim.keymap.set(mode, rhs, lhs, {buffer = event.buf})
    end

    -- Estos atajos ya están definidos en Neovim v0.11
    bufmap('n', 'K', '<cmd>lua vim.lsp.buf.hover()<cr>')
    bufmap('n', 'grr', '<cmd>lua vim.lsp.buf.references()<cr>')
    bufmap('n', 'gri', '<cmd>lua vim.lsp.buf.implementation()<cr>')
    bufmap('n', 'grt', '<cmd>lua vim.lsp.buf.type_definition()<cr>')
    bufmap('n', 'grn', '<cmd>lua vim.lsp.buf.rename()<cr>')
    bufmap('n', 'gra', '<cmd>lua vim.lsp.buf.code_action()<cr>')
    bufmap('n', 'gO', '<cmd>lua vim.lsp.buf.document_symbol()<cr>')
    bufmap({'i', 's'}, '<C-s>', '<cmd>lua vim.lsp.buf.signature_help()<cr>')
  end,
})
Enter fullscreen mode Exit fullscreen mode

Esta es la descripción de todos los atajos que están relacionados con el cliente LSP.

  • <Ctrl-]>: Saltar a definición del símbolo que está debajo del cursor.
  • gq: Formatea el código seleccionado. Este atajo utilizará el servidor LSP si es posible.
  • [d: Saltar al diagnóstico anterior del archivo actual.
  • ]d: Saltar al siguiente diagnóstico del archivo actual.
  • <Ctrl-w>d: Mostrar diagnósticos de la línea actual.
  • K: Muestra información sobre símbolo debajo del cursor.
  • grr: Listar referencias del símbolo debajo del cursor.
  • gri: Mostrar implementaciones del símbolo debajo del cursor.
  • grt: Saltar a definición de tipo del símbolo debajo del cursor.
  • grn: Renombrar todas las referencias del símbolo debajo del cursor.
  • gra: Listar "code actions" disponibles en la posición del cursor.
  • g0: Listar todos los símbolos en el archivo actual
  • <Ctrl-s>: En modo de inserción, mostrar argumentos de la función debajo del cursor.

Autocompletado de código

Vale la pena mencionar que Neovim provee un mecanismo de completado de código, lo pueden encontrar en la documentación como ins-completion. Desafortunadamente no es como en otros editores. No se activa de manera automática. Y en versiones antiguas no ofrece soporte para expandir "snippets" de código.

Para obtener un autocompletado verdadero con soporte para snippets podemos usar mini.nvim. mini.nvim es una colección de módulos escritos en lua, está diseñado para complementar las funcionalidades nativas de Neovim. Para habilitar autocompletado con snippets podemos usar estos dos módulos.

require('mini.snippets').setup({})
require('mini.completion').setup({})
Enter fullscreen mode Exit fullscreen mode

Cabe destacar que mini.nvim es compatible con Neovim v0.9 así que podrán usarlo incluso en versiones antiguas.

mini.completion utiliza el mecanismo nativo de Neovim, esto quiere decir que para controlarlo los mismos atajos que Neovim define por defecto.

  • <Down>: Selecciona el siguiente item en la lista.

  • <Up>: Selecciona el item anterior en la lista.

  • <Ctrl-n>: Selecciona e inserta el contenido del siguiente item en la lista.

  • <ctrl-p>: Selecciona e inserta el contenido del item anterior.

  • <Ctrl-y>: Confirma el item seleccionado.

  • <Ctrl-e>: Cancela el proceso de completado y esconde el menú.

  • <Enter>: Si el item fue seleccionado con <Up> o <Down> confirma la selección. Si no hay ningún item seleccionado, esconde el menú. Si no, inserta un salto de línea.

Ejemplo completo

Eso es todo. Ya tenemos todo lo necesario para empezar a usar el cliente LSP de Neovim.

Si tienen acceso a Neovim v0.11 o una versión mayor, esto es todo lo que necesitan:

-- NOTA: Esta configuración es para Neovim v0.11 o una versión mayor

require('mini.snippets').setup({})
require('mini.completion').setup({})

vim.lsp.enable({'gopls', 'rust_analyzer'})
Enter fullscreen mode Exit fullscreen mode

Si quieren una configuración compatible en versiones anteriores:

-- NOTE: Esta configuración es compatible con Neovim v0.9 o una versión mayor

---
-- Autocompletado de código
---

require('mini.snippets').setup({})
require('mini.completion').setup({})

---
-- LSP
---

-- Estos atajos ya están definidos en Neovim v0.10
if vim.fn.has('nvim-0.11') == 0 then
  -- NOTA: vim.diagnostic.goto_* fue renombrado en v0.11
  -- es por eso que este bloque está bajo una condición
  vim.keymap.set('n', '[d', '<cmd>lua vim.diagnostic.goto_prev()<cr>')
  vim.keymap.set('n', ']d', '<cmd>lua vim.diagnostic.goto_next()<cr>')
  vim.keymap.set('n', '<C-w>d', '<cmd>lua vim.diagnostic.open_float()<cr>')
  vim.keymap.set('n', '<C-w><C-d>', '<cmd>lua vim.diagnostic.open_float()<cr>')
end

vim.api.nvim_create_autocmd('LspAttach', {
  callback = function(event)
    local bufmap = function(mode, rhs, lhs)
      vim.keymap.set(mode, rhs, lhs, {buffer = event.buf})
    end

    -- Estos atajos ya están definidos en Neovim v0.11
    bufmap('n', 'K', '<cmd>lua vim.lsp.buf.hover()<cr>')
    bufmap('n', 'grr', '<cmd>lua vim.lsp.buf.references()<cr>')
    bufmap('n', 'gri', '<cmd>lua vim.lsp.buf.implementation()<cr>')
    bufmap('n', 'grn', '<cmd>lua vim.lsp.buf.rename()<cr>')
    bufmap('n', 'gra', '<cmd>lua vim.lsp.buf.code_action()<cr>')
    bufmap('n', 'gO', '<cmd>lua vim.lsp.buf.document_symbol()<cr>')
    bufmap({'i', 's'}, '<C-s>', '<cmd>lua vim.lsp.buf.signature_help()<cr>')
  end,
})

-- Esta función usará el método adecuado para configurar un servidor LSP.
-- Ya que vim.lsp.enable() sólo está disponible en versiones más recientes.
local function lsp_setup(server, opts)
  if vim.fn.has('nvim-0.11') == 0 then
    require('lspconfig')[server].setup(opts)
    return
  end

  if not vim.tbl_isempty(opts) then
    vim.lsp.config(server, opts)
  end

  vim.lsp.enable(server)
end

lsp_setup('gopls', {})
lsp_setup('rust_analyzer', {})
Enter fullscreen mode Exit fullscreen mode

Gracias por su tiempo. Si este artículo les pareció útil y quieren apoyar mis esfuerzos para crear más contenido pueden dejar una propina en ko-fi.com/vonheikemen.

buy me a coffee

Latest comments (10)

Collapse
 
gorjes4444 profile image
Gorjes4444

Hola, muy bueno tu post, pero tengo dos problemas, ojalá me puedas guiar.
Tengo instalado neovim en windows y esta es mi configuración de init.lua

Image description

Image description

Un problema que tengo es que cuando paso al modo insertar me sale el mensaje de error de la imgen de abajo. Luego puedo insertar pero no puedo quitar ese error.

El otro problema es que no tengo opciones de autocompletado con palabras del mismo buffer y no se como configurar esa opción. Entiendo que hay que poner

sources = {
{ name = 'buffer' }
}
})
O algo así pero no entiendo en que archivo debería hacerlo. Soy muy nuevo en esto y estoy bastante perdido. Sepan comprender y acepto consejos.
Saludos

Collapse
 
vonheikemen profile image
Heiker

Intenta colocar tus nuevos plugins fuera de las dependencias de lsp-zero. Probablemente hay un problema en el orden en que se cargan los módulos.

{'folke/tokyonight.nvim'},
{
  'nvim-lualine/lualine.nvim',
  requires = {'nvim-tree/nvim-web-devicons', opt = true}
},
{'nvim-lua/plenary.nvim'},
{'j-morano/buffer_manager.nvim'},
{
  'VonHeikemen/lsp-zero.nvim',
  branch = 'v2.x',
  dependencies = {
    -- Soporte LSP
    {'neovim/nvim-lspconfig'},
    {'williamboman/mason.nvim'},
    {'williamboman/mason-lspconfig.nvim'},

    -- Autocompletado
    {'hrsh7th/nvim-cmp'},
    {'hrsh7th/cmp-nvim-lsp'},
    {'L3MON4D3/LuaSnip'},
  }
},
Enter fullscreen mode Exit fullscreen mode

Con el otro problema. Puedes configurar el autocompletado en tu archivo init.lua. Debes tener en cuenta que cada "source" que agregas a nvim-cmp es un plugin nuevo que debes instalar. Entonces, debes instalar este plugin: cmp-buffer. Luego, usa el modulo cmp para configurar la opción sources. Así.

local lsp = require('lsp-zero').preset({})

lsp.on_attach(function(client, bufnr)
  lsp.default_keymaps({buffer = bufnr})
end)

lsp.setup()

local cmp = require('cmp')

cmp.setup({
  sources = {
    {name = 'nvim_lsp'},
    {name = 'buffer'},
  }
})
Enter fullscreen mode Exit fullscreen mode

Debes usar cmp.setup() después de configurar lsp-zero, así te aseguras de que tu configuración sobreescriba la de lsp-zero.

Aqui {name = 'nvim_lsp'} pertenece a este plugin cmp-nvim-lsp, ese ya lo tienes instalado, esta en las dependencias de lsp-zero, pero debes colocarlo para no perder el autocompletado del cliente LSP. Ahora, {name = 'buffer'} es cmp-buffer. Esto es importante: la propiedad name no es el nombre del plugin. Cuando vas a instalar un "source" para nvim-cmp no intentes adivinar, revisa la documentación para saber qué valor debería tener name.

Collapse
 
gorjes4444 profile image
Gorjes4444

¡Muchisimas gracias hermano! Gracias por contestar y gracias por la paciencia.

Collapse
 
peterr2d2 profile image
Pedro Farias

Hola disculpa por las molestias soy nuevo con lo de las configuraciones y conozco muy poco sobre nvim y lua, segui los pasos que tienes en el post pero tengo el siguiente error y no se muy bien a que se debe

Image description

espero me puedas ayudar

Collapse
 
vonheikemen profile image
Heiker

Este archivo está creando un conflicto.

/home/arthur/.config/nvim/lua/lsp-zero/init.lua
Enter fullscreen mode Exit fullscreen mode

Impide que neovim cargue el script que está dentro del plugin. Porque estás creando otro módulo con el nombre lsp-zero.

Debes crear otro módulo con un nombre único para evitar conflictos con cualquier plugin. Puedes crear uno llamado user y colocar tu script ahí.

/home/arthur/.config/nvim/lua/user/lsp-zero/init.lua
Enter fullscreen mode Exit fullscreen mode

Luego en tu configuración lo llamas de esta manera.

require('user.lsp-zero')
Enter fullscreen mode Exit fullscreen mode
Collapse
 
shayredd22 profile image
ShayRedD12 • Edited

tengo una pregnta...
lo que pasa es que me sale este error al tratar de instalar el server de phppactor
adjunto pantallazo del error
Image description

solo me deja instalar el de instelepehense pero cuando trato de escribir algo en un archivo php no sale ninguna sujerencia

Collapse
 
vonheikemen profile image
Heiker

Para instalar phpactor necesitas composer.

Si quieres saber si un servidor LSP está activo en un archivo ejecuta el comando :LspInfo.

Collapse
 
vantyc profile image
vantyc

*Espectacular trabajo! en unos minutos has resuelto mi busqueda de semanas. Gracias!
1.- Se puede hacer lo mismo con vim, quiza con otro conjunto de plugins?
2.- Cuando aparecen errores en el código pre-existente como sacas el menú de correcciones o el detalle del error en neovim?

Collapse
 
vonheikemen profile image
Heiker

1.- Se puede hacer lo mismo con vim, quiza con otro conjunto de plugins?

Creo que sí. Se puede usar vim-lsp para integrar un cliente lsp. Luego tienes vim-lsp-settings, es como un complemento de vim-lsp, es una colección de configuraciones para servidores LSP. También parece tener un método para instalar servidores. La integración con el autocompletado puede hacerse con asyncomplete,vim (plugin del mismo autor de vim-lsp) o ddc.vim que también es muy bueno.

2.- Cuando aparecen errores en el código pre-existente como sacas el menú de correcciones o el detalle del error en neovim?

El mensaje de error en la ventana flotante se activa con el atajo g + l. Las correcciones (en neovim le dicen "code actions") se activan con F4.