Guía completa para configurar NeoVim para desarrolladores - parte 2

Guía completa para configurar NeoVim para desarrolladores - parte 2

Antes de empezar, te recomiendo que revises la primera parte, donde mostré cómo configurar Neovim desde cero, empezando por la instalación y configuración de la consola y terminando con un montón de plugins imprescindibles para trabajar con código:

Guía completa de configuración de NeoVim para desarrolladores - parte 1

Neovim (nvim) es el mismo vim, pero mejorado, reescrito y que se ha llevado a su lado a buena parte de la comunidad del editor original. Hoy en día este proyecto ha superado ampliamente al vim original en las estadísticas de github (34 vs 75k estrellas en 2024), así que si por alguna razón decidiste empezar a programar en la consola

El material de abajo se lee mejor después de haber leído y repetido lo que describí en la primera parte. Pero en caso de que ya tengas una configuración lista y solo necesites añadirle alguno de los plugins descritos a continuación, podrás hacerlo sin problemas: he procurado describir todos los plugins de forma independiente entre sí, en subsecciones separadas.

Antes de ponernos con la configuración del editor, propongo afinar un poco nuestra consola —wezterm—, la que ajustamos y configuramos en la primera parte.

Muestro la configuración tanto del editor como de la consola para Mac, por eso las siguientes acciones con la consola son válidas para usuarios de macOS. Si usas linux, lo más probable es que no tengas los problemas de consola que se resuelven a continuación y puedas pasar directamente a la configuración de los plugins.

Mapeo de la tecla Command para trabajar con wezterm y neovim

Trabajando me di cuenta de que me resulta mucho más cómodo mapear distintas combinaciones a la tecla Command. Por ejemplo, por defecto en vim/neovim, para pasar a la ventana contigua hay que pulsar Control + w, lo cual, dicho suavemente, no es demasiado cómodo. Es mucho más cómodo redefinir todas las combinaciones de Control a Command. Establecer combinaciones en neovim no es complicado, normalmente se hace mediante el comando

vim.api.nvim_set_keymap(mode, combination, command, options...)

Pero la particularidad de wezterm, como la de la mayoría de las demás consolas para mac, es que no le transmiten al editor la combinación en un formato legible (si sabes cómo hacerlo de una forma más sencilla, escríbelo en los comentarios). La forma en que lo hago yo se ve así: en la configuración de wezterm bindeamos todas las combinaciones que necesitamos como símbolos utf8, que se enviarán a neovim. Después, en la configuración de neovim, bindeamos las combinaciones ya sobre los símbolos utf-8 transmitidos.

Configuración en wezterm:

--- cmd+keys that we want to send to neovim.
local super_vim_keys_map = {
    -- Command + s: saving file
	s = utf8.char(0xAA),
    -- Command + e: scroll downwords (ctrl + e analog)
	e = utf8.char(0xAB),
    -- Command + y: scroll upwords (ctrl + y analog)
	y = utf8.char(0xAC),
    -- Command + h: go to prev tab
	h = utf8.char(0xAD),
    -- Command + l: go to next tab
	l = utf8.char(0xAE),
    -- Command + w: close current tab
	w = utf8.char(0xAF),
    -- Command + t: find file toogle (NvimTree)
	t = utf8.char(0xA1),
}
 
local function bind_super_key_to_vim(key)
	return {
		key = key,
		mods = 'CMD',
		action = wezterm.action_callback(function(win, pane)
			local char = super_vim_keys_map[key]
			if char and is_vim(pane) then
				-- pass the keys through to vim/nvim
				win:perform_action({
					SendKey = { key = char, mods = nil },
				}, pane)
			else
				win:perform_action({
					SendKey = {
						key = key,
						mods = 'CMD'
					}
				}, pane)
			end
		end)
	}
end
 
local keys = {
    ...,
    
    bind_super_key_to_vim('s'),
    bind_super_key_to_vim('h'),
    bind_super_key_to_vim('l'),
    bind_super_key_to_vim('w'),
    bind_super_key_to_vim('e'),
    bind_super_key_to_vim('y'),
    bind_super_key_to_vim('t'),
    bind_super_key_to_vim('['),
    bind_super_key_to_vim(']'),
    bind_super_key_to_vim('n'),
    bind_super_key_to_vim('m')
}
 
config.keys = keys
 
return config

El código completo de la configuración se puede encontrar aquí.

Y a continuación mapeamos estos símbolos utf8 ya del lado de neovim. Creamos un archivo lua donde iremos escribiendo todos los mapeos: combinations.lua:

local keymap = vim.api.nvim_set_keymap
local default_opts = {noremap = true, silent = true}
 
-- cmd+s: save file
keymap("n", "<Char-0xAA>", "<cmd>write<cr>", default_opts)
-- cmd+e: scroll downwords
keymap("n", "<Char-0xAB>", "<C-e>", default_opts)
-- cmd+e: scroll upwords
keymap("n", "<Char-0xAC>", "<C-y>", default_opts)
-- cmd+h: next tab
keymap("n", "<Char-0xAD>", "<cmd>BufferPrevious<cr>", default_opts)
-- cmd+l: last tab
keymap("n", "<Char-0xAE>", "<cmd>BufferNext<cr>", default_opts)
-- cmd+w: close current tab
keymap("n", "<Char-0xAF>", "<cmd>BufferClose<cr>", default_opts)
-- cmd+t: find file toogle 
keymap("n", "<Char-0xA1>", "<cmd>NvimTreeFindFile<cr>", default_opts)
 
-- cmd+1: open left bar  
keymap('n', '<Char-0xA4>', '<cmd>NvimTreeToggle<cr>', default_opts)

Ahora incluimos este archivo en la sección con require en init.lua:

...
require"combinations"

Ahora reiniciamos neovim y comprobamos: si abrimos cualquier archivo y pulsamos command + t, neovim te llevará automáticamente a ese archivo en el árbol de archivos.

Ahora, si vuelves al archivo y pulsas Command + e, nvim empezará a hacer scroll hacia abajo en el archivo; Command + y, hacia arriba. Command + s guardará el archivo, y Command + h / Command + l te moverán entre las distintas pestañas dentro de neovim. Ahora podemos pasar a la configuración de los plugins.

Telescope - búsqueda por archivos y por contenido

El primer plugin que uso constantemente es Telescope. Hoy en día es el plugin más popular para buscar por archivos y por contenido. Lo uso desde hace ya un par de años y puedo decir que, en la mayoría de los casos, el plugin cumple perfectamente con su cometido.

Para buscar por el contenido de los archivos, el plugin usa la utilidad de búsqueda por consola fzf. Antes de pasar a los plugins, necesitamos instalarla:

brew install fzf

Y tras la instalación, cargarla en la sesión actual de la terminal:

source <(fzf --zsh)

Luego, en esa misma sesión, abrimos nvim y creamos el archivo telescope_config.lua:

-- Use vim.keymap.set instead of vim.api.nvim_set_keymap
local keymap = vim.keymap.set
 
-- Map <leader>f to fzf-lua's file search
keymap("n", "<leader>f", require("fzf-lua").files, { desc = "Fzf files" })
 
-- Map <leader>g to fzf-lua's live grep
keymap("n", "<leader>g", require("fzf-lua").live_grep, { desc = "Fzf live grep" })

Incluimos los plugins necesarios y la configuración en init.lua:

...
 
-- Telescope
Plug('nvim-lua/plenary.nvim') --for fzf
Plug('nvim-telescope/telescope.nvim', { [ 'tag' ] = '0.1.4' })
Plug('ibhagwan/fzf-lua', {['branch'] = 'main'})
 
...
require"telescope_config"

Reiniciamos, saltamos el error pulsando enter y ejecutamos :PlugInstall. Tras la instalación, reiniciamos una vez más. Ahora pulsamos la combinación \ + f

y vemos la ventana de búsqueda por archivos:

Luego pulsamos la combinación \ + g y vemos la ventana de búsqueda por contenido:

Autosession

Autosession es un plugin que añade algo muy habitual para nosotros: recuerda qué archivos estaban abiertos antes de cerrar nvim y los abre automáticamente la próxima vez que se abra nvim.

Creamos el archivo autosession.lua:

require'auto-session'.setup {
  suppressed_dirs = { "~/", "~/Projects", "~/Downloads", "/"},
  auto_restore_last_session = true
}

Luego, en init.lua, incluimos el archivo y su configuración en init.lua:

Plug('rmagatti/auto-session')
...
require"autosession"

Instalamos, reiniciamos y comprobamos:

Comment - comentarios en el código

Ahora añadamos otra capacidad básica: la posibilidad de comentar y descomentar código. Para esto uso el plugin Comment: funciona out of the box y es compatible con treesitter, lo que nos da soporte para la mayoría de los lenguajes de programación.

Creamos el archivo comment_config.lua:

require('Comment').setup()

Luego incluimos el plugin y su configuración en init.lua:

...
Plug('numToStr/Comment.nvim')
...
require("comment_config")

Instalamos, reiniciamos y, a continuación, seleccionando cualquier fragmento de código mediante el modo visual (Shift+V + ↑/↓), con la combinación gc podemos comentar y descomentar de nuevo el fragmento de código seleccionado:

Trouble

Nvim tiene sus propias herramientas para mostrar los errores en el código, pero llegar a ellas, dicho suavemente, no es sencillo.

Trouble es un plugin que añade una interfaz para mostrar todos los errores del proyecto abierto. Trouble es compatible con el servidor lsp, lo que nos permite ver todos los errores de la forma habitual, con comentarios comprensibles.

Creamos la configuración trouble_config.lua:

require('trouble').setup()
 
vim.keymap.set("n", "<leader>xx", function() require("trouble").toggle() end)
vim.keymap.set("n", "<leader>xw", function() require("trouble").toggle("workspace_diagnostics") end)
vim.keymap.set("n", "<leader>xd", function() require("trouble").toggle("document_diagnostics") end)
vim.keymap.set("n", "<leader>xq", function() require("trouble").toggle("quickfix") end)
vim.keymap.set("n", "<leader>xl", function() require("trouble").toggle("loclist") end)
vim.keymap.set("n", "gR", function() require("trouble").toggle("lsp_references") end)

init.lua:

...
Plug('folke/trouble.nvim')
 
...
require"trouble_config"
...

El plugin trae de fábrica un conjunto de combinaciones que se pueden usar, pero yo he reconfigurado la apertura de la interfaz a la combinación Command + [.

Para hacer lo mismo, hay que volver a la configuración de wezterm y añadir otra combinación para abrir Trouble mediante Command:

wezterm.lua:

-- Command + [: open trouble window
	['['] = utf8.char(0xA2),
    -- Command + ]: close trouble window 
	[']'] = utf8.char(0xA3),
 
    ...
 
    bind_super_key_to_vim('['),
    bind_super_key_to_vim(']'),
    ...

Luego añadimos estas combinaciones en la configuración de nvim:

combinations.lua:

...
-- cmd+[: get troubles
keymap("n", "<Char-0xA2>", "<cmd>Trouble diagnostics toggle<cr>", default_opts)
-- cmd+]: close troubles
keymap("n", "<Char-0xA3>", "<cmd>TroubleClose<cr>", default_opts)
...

Reiniciamos y comprobamos:

git-blame - historial interactivo de commits

git-blame es un plugin minimalista que hace lo mismo que estamos acostumbrados a ver en los IDE cuando abrimos las anotaciones en el código: muestra el autor y el nombre del commit.

El plugin no requiere configuración y, para activarlo, nos basta con incluir el plugin en init.lua:

Plug 'f-person/git-blame.nvim'

Y instalarlo. Después nos situamos sobre cualquier línea de un proyecto con git y vemos:

Conclusión

Con esto termina la configuración básica. He descrito los plugins más esenciales, los que dan las capacidades fundamentales a las que estamos acostumbrados en los distintos IDE.

Mi configuración es algo más amplia de lo que mostré arriba. Por ejemplo, ahí hay plugins para trabajar con tests, para un trabajo más avanzado con git, para resolver conflictos de git, y para buscar y depurar código de forma más cómoda.

Pero, para no alargar el texto, describiré estos plugins y su configuración en artículos aparte.

Mi configuración completa, que actualizo constantemente, se puede encontrar aquí:

GitHub - itxor/go-rust-nvim-config

Contribute to itxor/go-rust-nvim-config development by creating an account on GitHub.

Configuración de wezterm:

wezterm_config/wezterm.lua at main · itxor/wezterm_config

Contribute to itxor/wezterm_config development by creating an account on GitHub.

También llevo un canal de telegram en inglés con un digest de material sobre Go:

https://t.me/the_dev_signal

Y un canal de telegram personal, donde escribo distintas notas, herramientas y comparto experiencia:

https://t.me/junsenior

Y no dejes de suscribirte a los nuevos materiales de este sitio, que pronto empezarán a salir con más frecuencia :)