Guia completo de configuração do NeoVim para desenvolvedores - parte 2

Guia completo de configuração do NeoVim para desenvolvedores - parte 2

Antes de começar, recomendo dar uma olhada na primeira parte, onde mostrei como configurar o Neovim do zero, começando pela instalação e configuração do terminal e terminando com uma série de plugins essenciais para trabalhar com código:

Guia completo para configurar o NeoVim para desenvolvedores - parte 1

Neovim (nvim) é o mesmo vim, só que melhorado, reescrito e que atraiu para o seu lado boa parte da comunidade do editor original. Hoje esse projeto ultrapassou de longe o vim original nas estatísticas do github (34 vs 75k estrelas em 2024), então se por algum motivo você decidiu começar a programar no terminal

O material abaixo é melhor lido depois de ler e reproduzir o que foi descrito na primeira parte. Mas, caso você já tenha uma configuração pronta e precise adicionar algum dos plugins descritos abaixo, você conseguirá fazer isso sem problemas: procurei descrever todos os plugins de forma independente uns dos outros, em subseções separadas.

Antes de partir para a configuração do editor, proponho ajustar um pouco o nosso terminal — o wezterm, que instalamos e configuramos na primeira parte.

Estou mostrando a configuração tanto do editor quanto do terminal para Mac, então as ações seguintes com o terminal servem para usuários de Macos. Se você usa Linux, é bem provável que os problemas com o terminal resolvidos abaixo nem apareçam para você, e pode ir direto para a configuração dos plugins.

Mapeando a tecla Command para trabalhar com wezterm e neovim

Ao longo do trabalho percebi que é muito mais confortável mapear diferentes combinações na tecla Command. Por exemplo, por padrão no vim/neovim, para ir até a janela vizinha é preciso apertar Control + w, o que, para dizer o mínimo, não é muito prático. É bem mais confortável redefinir todas as combinações de Control para Command. Definir combinações no neovim não é difícil, normalmente isso é feito pelo comando

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

Mas a particularidade do wezterm, assim como da maioria dos outros terminais para mac, é que eles não passam a combinação para o editor de forma legível (se você sabe como fazer isso de um jeito mais simples, escreve nos comentários). A forma como eu faço é a seguinte: fazemos o bind, no config do wezterm, de todas as combinações que precisamos como caracteres utf8, que serão enviados ao neovim. Depois, no config do neovim, fazemos o bind das combinações usando esses caracteres utf-8 já recebidos.

Config no 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

O código completo do config pode ser encontrado aqui.

E em seguida mapeamos esses caracteres utf8 já do lado do neovim. Criamos um arquivo lua onde vamos definir todos os mapeamentos — 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)

Agora incluímos esse arquivo na seção com require no init.lua:

...
require"combinations"

Agora reiniciamos o neovim e testamos: se você abrir algum arquivo e apertar command + t, o neovim vai automaticamente te levar até esse arquivo na árvore de arquivos.

Agora, se você voltar para o arquivo e apertar Command + e, o nvim vai começar a rolar o arquivo para baixo, Command + y — para cima. Command + s salva o arquivo, e Command + h / Command + l alternam entre as diferentes abas dentro do neovim. Agora podemos partir para a configuração dos plugins.

Telescope - busca por arquivos e conteúdo

O primeiro plugin que uso constantemente é o Telescope. No momento, é o plugin mais popular para busca por arquivos e por conteúdo. Uso ele já há alguns anos e posso dizer que, na maioria dos casos, o plugin dá conta muito bem das suas tarefas.

Para a busca pelo conteúdo dos arquivos, o plugin usa a ferramenta de busca no terminal fzf. Antes de partir para os plugins, precisamos instalá-la:

brew install fzf

E, depois de instalar, carregá-la na sessão atual do terminal:

source <(fzf --zsh)

Depois, nessa mesma sessão, abrimos o nvim e criamos o arquivo 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" })

Incluímos os plugins necessários e o config no 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, pulamos o erro apertando enter e executamos :PlugInstall. Depois da instalação, reiniciamos mais uma vez. Agora apertamos a combinação \ + f

e vemos a janela de busca por arquivos:

Depois apertamos a combinação \ + g e vemos a janela de busca por conteúdo:

Autosession

Autosession é um plugin que adiciona algo muito familiar para nós — ele memoriza quais arquivos estavam abertos antes de fechar o nvim e os abre automaticamente na próxima vez que o nvim for aberto.

Criamos o arquivo autosession.lua:

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

Depois, no init.lua, incluímos o arquivo e o config dele no init.lua:

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

Instalamos, reiniciamos e testamos:

Comment - comentários no código

Agora vamos adicionar mais um recurso básico — a possibilidade de comentar e descomentar código. Para isso eu uso o plugin Comment — ele funciona out of the box e tem suporte a treesitter, o que nos dá suporte à maioria das linguagens de programação.

Criamos o arquivo comment_config.lua:

require('Comment').setup()

Depois incluímos o plugin e o config dele no init.lua:

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

Instalamos, reiniciamos e, em seguida, selecionando qualquer trecho de código pelo modo visual (Shift+V + ↑/↓), com a combinação gc podemos comentar e descomentar de volta o trecho de código selecionado:

Trouble

O nvim tem suas próprias ferramentas para exibir erros no código, mas chegar até elas, para dizer o mínimo, não é nada simples.

Trouble é um plugin que adiciona uma interface para exibir todos os erros do projeto aberto. O Trouble tem suporte ao lsp-server, o que nos permite ver todos os erros de forma familiar, com comentários claros.

Criamos o config 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"
...

O plugin já vem com um conjunto de combinações prontas para uso, mas eu reconfigurei a abertura da interface para a combinação Command + [.

Para fazer o mesmo, é preciso voltar ao config do wezterm e adicionar mais uma combinação para abrir o Trouble pelo 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(']'),
    ...

Depois adicionamos essas combinações no config do 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 e testamos:

git-blame - histórico interativo de commits

git-blame é um plugin minimalista que faz a mesma coisa que estamos acostumados a ver na IDE quando abrimos as anotações no código: exibe o autor e o nome do commit.

O plugin não precisa de configuração e, para ativá-lo, basta incluí-lo no init.lua:

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

E instalá-lo. Depois, passando o cursor sobre qualquer linha de um projeto com git, vemos:

Conclusão

Com isso, a configuração básica está concluída. Descrevi os plugins mais essenciais, que dão os recursos fundamentais aos quais estamos acostumados nas diversas IDEs.

Meu config é um pouco mais amplo do que o que mostrei acima. Por exemplo, lá tem plugins para trabalhar com testes, para um trabalho mais avançado com o git, para resolver conflitos de git, para uma busca e depuração de código mais convenientes.

Mas, para não alongar demais o texto, vou descrever esses plugins e a configuração deles em artigos separados.

Meu config completo, que é atualizado constantemente, pode ser encontrado aqui:

GitHub - itxor/go-rust-nvim-config

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

Config do wezterm:

wezterm_config/wezterm.lua at main · itxor/wezterm_config

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

Também mantenho um canal no telegram em inglês com um resumo de materiais sobre Go:

https://t.me/the_dev_signal

E um canal autoral no telegram, onde escrevo diversas notas, ferramentas e compartilho experiências:

https://t.me/junsenior

E não deixe de se inscrever para os novos materiais deste site, em breve eles vão começar a sair com mais frequência :)