Apuntes mientras aprendo sobre software y computadoras.

Computación

Cómo instalar un servidor de lenguaje en Neovim de forma manual


En este apunte voy a revisar cómo instalar un servidor de lenguaje en Neovim sin utilizar ningún plugin externo para organizarlo.

El objetivo de todo esto es conseguir darle soporte a distintos lenguajes de programación dentro de este editor de texto.

Estuve practicando bastante con Neovim, pero todo lo que hice hasta este punto fue utilizarlo para escribir texto narrativo o ensayos. Por ejemplo esta misma entrada esta siendo escrita utilizando Markdown dentro de Neovim. Pero nunca lo utilicé para escribir código de computadora.

Eso va a cambiar en cuanto podamos poner esto en marcha. Pero antes tengo que mencionar tres cosas:

Ahora sin más vueltas…

¿Qué es un servidor de lenguaje? ¿Qué significa “lsp”?

Estoy intentando ir lo más rápido posible, por lo que este es mi super resumen:

  • LSP quiere decir “Language Server Protocol” y es un conjunto de especificaciones que dice cómo tiene que comunicarse un servidor de lenguaje con un cliente.
  • Un “Language Server” es un servidor de lenguaje de acuerdo al protocolo LSP. Contiene información y funcionalidades de un lenguaje determinado (por ejemplo revisión de sintaxis o diagnóstico de errores) que el cliente puede usar.
  • Neovim funciona como un cliente para el servidor de lenguaje, y realiza la comunicación entre el servidor y nuestro archivo.

A modo de simplificarlo, digamos que queremos escribir dentro de Neovim con en el lenguaje Python. Queremos tener herramientas de auto formato, revisión de errores de sintaxis, ese tipo de cosas.

Para conseguir ese tipo de herramientas necesitamos un servidor de lenguaje externo al programa. Ese servidor va a descansar en nuestra computadora y Neovim va a comunicarse con el por medio del protocolo LSP. Eso va a decirle al programa cómo darle formato al código de Python y todo lo demás.

Estas dos cosas son elementos separados. Ya tenemos Neovim que va a actuar como cliente, necesitamos conseguir un Servidor de Lenguaje específico a nuestras necesidades.

Este servidor de lenguaje no tienen nada que ver con la forma en que ejecutamos el código. Utilizar LSP principalmente nos va a habilitar nuevas opciones de escritura en el programa.

Instalar un lsp de forma manual en Neovim

Voy a tratar de resumir esto de la forma más directa que puedo.

Paso 1: conseguir el servidor de cada lenguaje

Ahora necesitamos descargar cada servidor de lenguaje propiamente dicho. Por suerte conseguir esto es sencillo.

Para este ejemplo voy a descargar el servidor de lenguaje para Bash a modo de ejemplo.

Podemos conseguir una lista de estos posibles servidores disponibles siguiendo este enlace.

Esta es otra lista de servidores de lenguaje, y que nos dice que opciones agrega cada servidor.

Los detalles de cómo descargar cada servidor se encuentra en cada sitio en particular.

Entonces para Bash voy a utilizar bash-language-server.

Paso 1.5: instalar dependencias específicas para Bash

Distintos servidores de lenguaje necesitan distintas dependencias. Una vez más, eso podemos encontrarlo en el sitio de cada server.

En el caso de Bash LSP necesitamos: “shellcheck” para revisar el código y “shfmt” para poder darle auto formato.

Entonces agregamos en el sistema:

sudo apt install shellcheck
sudo apt install shfmt

Cómo instalar nodejs en el sistema

Tal vez esto no es completamente necesario, pero ya que estoy en el tema de agregar dependencias extra no viene mal mencionarlo.

Antes de continuar tenemos que revisar si tenemos “nodejs” en el sistema. Tengan en cuenta que escribo esto utilizando Linux Mint, pero los pasos se pueden ajustar a otos sistemas operativos.

Primero tengo que revisar las versiones de “node” y “npm” hacer:

node -v 
npm -v

Siendo que seguro están desactualizados, lo mejor va a ser empezar desinstalando lo que tenemos para empezar desde cero:

sudo apt remove nodejs npm

Y luego instalamos NVM con el siguiente comando:

wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh | bash

Con esto voy a tener también la última versión de NPM. Cierro la terminal y vuelvo a abrirla para que la instalación tome efecto.

Ahora instalo “node.js” con este comando:

nvm install –lts

Puedo revisar la nueva versión con:

node -v

Paso 2: Instalar el servidor del lenguaje

Otra vez, eso depende de cada caso en particular, y lo más seguro es que voy a encontrar esa información en el sitio de cada server.

Pero en nuestro caso particular tenemos para instalar bash language server de forma global:

npm i -g bash-language-server

Y para verificar que todo funciona:

bash-language-server –help

Si no aparece ningún error, el servidor de lenguaje de bash ya se encuentra en mi equipo.

Todo esto lo hacemos de forma global en nuestro equipo, todavía no tuvimos necesidad de abrir Neovim.

Paso 3: Configurar el servidor

Esta es una lista de todas las configuraciones disponibles en nvim-lspconfig: lista de configuraciones.

Si instalamos ese plugin, vamos a encontrar todas esas configuraciones desde el vamos. Pero en esta oportunidad intento hacerlo de forma manual.

En nuestro caso encontramos una posible configuración en la página de bash language server.

Lo siguiente que tenemos que hacer es crear un archivo llamado “bashls.lua” en el directorio dónde guardamos las configuraciones de Neovim.

Y agregamos esto:

vim.api.nvim_create_autocmd('FileType', {
  pattern = 'sh',
  callback = function()
    vim.lsp.start({
      name = 'bash-language-server',
      cmd = { 'bash-language-server', 'start' },
    })
  end,
})

Luego hacemos un llamado a ese archivo desde nuestro archivo “init.lua”:

require('bashls')

¿Cómo saber si el LSP funciona en Neovim?

Para revisar el diagnóstico del server de lenguaje tengo que usar este comando dentro de Neovim:

:checkhealth lsp

Y por ejemplo si tengo abierto un documento con la extension “sh” (por ejemplo voy a crear un archivo “test.sh” para probarlo )me dice que encuentra el servidor de Bash:

vim.lsp: Active Clients
bash language server

También tengo esto otro comando de diagnóstico:

:lua vim.cmd.edit(vim.lsp.get_log_path())

Que me va a dar mucha más información, aunque muchos de esos datos exceden mi objetivos de este texto.

Pero a final de cuentas lo importante es revisar si todo esto funciona o no sobre una pieza de código, ese es mi objetivo después de todo, y eso es lo que vamos a revisar a continuación

¿Necesito agregar root_folder en la configuración?

Voy a notar que en el diagnostico aparece:

root_dir=~/v:null

En la documentación de Neovim al utilizar LSP pide establecer un “directorio raíz” para que varios archivos en el mismo directorio puedan compartir el mismo servidor de lenguaje.

O al menos eso entiendo de este detalle específico.

La configuración de bash language server parece no pedir este directorio, así que por esta vez no necesito modificarlo. Pero la documentación explica por ejemplo cómo establecerlo para el lenguaje Python, los detalles pueden variar en cada caso.

Posible error de LSP: WARNING Log level DEBUG will cause degraded performance and high disk usage

Para resolver este problema, es posible que tenga en mi “init.lua algo como esto:

vim.lsp.set_log_level(‘debug’)

Eso me permite tener logs con más detalles. Pero si remuevo esa opción, remuevo este error y todavía recibo bastante información al ejecutar:

:lua vim.cmd.edit(vim.lsp.get_log_path())

Poner el LSP recién instalado en acción

Ya parece algo muy repetitivo pero… Las cosas que vamos a poder hacer con cada LSP dependen de ese LSP. Pero si hay algunas cosas que vienen establecidas desde el principio.

Lo importante de la configuración anterior que pusimos en “bashls.lua” a mi entender es que el servidor va a iniciarse cada vez que abramos un archivo con extension “sh” en Neovim.

Para empezar vamos a crear un nuevo archivo de Bash con esa extension “.sh”, y vamos a abrirlo en Neovim.

En ese archivo vamos a poner este código para probarlo:

#!/bin/bash
<br>message= "Testeando Bash LSP en Neovim" 
<br>echo "$message"

Ahora vamos a notara que si presionamos “Esc” para salir del modo de edición, bash language server va a mostrarnos los errores en el código. Por ejemplo en nuestro caso va a decir:

W message= "Testeando Bash LSP en Neovim" Remove space after = if trying to assign a value (for empty string, use var=’’ … ).

Donde nos da un aviso diciéndonos que tenemos que remover el espacio extra para declarar correctamente una variable.

Si queremos ejecutar el código de Bash directamente desde Neovim, luego de darle permisos de ejecución, utilizo el comando:

:!bash %

Y de esta forma ya estamos usando el servidor de lenguaje de Bash con Neovim, sin ningún intermediario extra.

Por otra parte Neovim cuenta con resaltado básico de lenguaje para Bash desde el vamos, de la misma forma que con Markdown. Esa es otra ventaja.

Activar otras funcionalidades utilizando LSP functions

Algunos detalles de LSP vienen mapeados de antemano, incluso si no agregamos ninguna configuración extra.

Para conocer todo lo que puedo hacer tengo el Manual original LSP de Neovim (en inglés).

Y por otra parte tengo este comando para utilizar en Neovim:

:lua =vim.lsp.get_clients()[1].server_capabilities

Lo que siguen son algunas cosas que puedo hacer en este momento, sin intervenir dentro de los archivos lua.

¿Cómo hago para ver la documentación del lenguaje utilizando LSP?

Puedo poner el cursor sobre la palabra de la que quiero conocer la documentación y utilizo el comando:

:lua vim.lsp.buf.hover()

Entonces me aparece una nueva ventana mostrándome esa parte de la documentación.

O de forma más sencilla, puedo presionar la letra “K”(en máyuscula) en “normal mode”.

¿Cómo activar el auto completar con LSP?

Digamos que estoy en “insert mode” y me encuentro escribiendo una palabra. Desde el vamos LSP me permite hacer un auto-completado que se activa de forma manual.

Con el cursor sobre esa palabra que quiero completar presiono la combinación “Ctrl-x Ctrl-o” (uno primero, luego el otro).

Y esto me despliega una ventana de auto completar (omni-completion).

¿Es una buena idea utilizar LSP en Neovim organizando la configuración de forma manual?

En mi experiencia escribiendo este texto, puedo decir que:

  • Si utilizamos pocos lenguajes de programación, es posible hacerlo. Aunque va a requerir un poco más de tiempo conseguir que todo funcione correctamente. No me imagino todo el esfuerzo que puede suponer hacer algo como esto para cinco, diez o más lenguajes.
  • No pude conseguir que funcione el auto formato. El servidor se conecta, tengo control de errores y auto completar pero nada más. Conseguir que todo funcione necesita algo más de experiencia.
  • Si bien es un tema interesante para aprender, existen ya tantas opciones para facilitar todo este trabajo de organizar LSP que es difícil no elegir una y ahorrar todo este esfuerzo.
  • A final de cuentas es mejor conseguir la configuración que nos resulte más cómoda. Esta configuración puede ser manual o creada por plugins. Lo importante es no detenernos tanto en los detalles y empezar a utilizar Neovim como una IDE para realizar otros proyectos.

Conclusión

Con esto le doy un cierre al apunte donde reviso cómo instalar un servidor de lenguaje (lsp) en Neovim de forma manual.

Por supuesto esto no reemplaza la lectura de la documentación oficial, simplemente estoy creando mi propio resumen para ayudarnos en caso de necesitar configurar Neovim en nuestra máquina desde cero.

Y además es bueno recordar que aunque pude poner a funcionar el servidor de lenguaje para Bash, seguramente hay formas más prácticas de hacerlo.

¿Encontraste algún error en la información? ¿Hay algo del texto que no fue bien explicado? Por favor, avísame con un correo electrónico para que pueda solucionar el problema.

La seguimos en el próximo apunte.

Recursos

Leave a Reply