NeoVim: init.lua, built in LSP e mais
Tags: neovim, vim, lua, lsp
Published: 2021-10-21 12:56:08

Preparei este post para quem quer migrar totalmente suas configurações para lua (nvim 0.5+) ou tá começando a configurar seu nvim hoje. ;)

Primeiro, você precisa escolher seu *plugin management*, eu escolhi usar o [paq-nvim](https://github.com/savq/paq-nvim) mas pode ser qualquer outro, tipo o [packer](https://github.com/wbthomason/packer.nvim).

Depois de instalar seu plugin manager, vamos criar os primeiros arquivos de configuração: **init.lua**, **lua/settings.lua** e **lua/keymaps.lua**.

## init.lua
É a entrada da suas configurações, vamos utilizar para importar as configurações em arquivos separados, assim fica mais organizado.

```lua
-- Settings & Keys
require 'settings'
require 'keymaps'
```

### lua/settings.lua
Concentra as configurações mais básicas

```lua
local g = vim.g
local opt = vim.opt
local cmd = vim.cmd

-- General
opt.compatible = false
opt.mouse = 'a'
opt.clipboard = 'unnamedplus'
opt.swapfile = false
opt.hidden = true
opt.history = 100
opt.lazyredraw = true
opt.synmaxcol = 240

-- Theme
opt.termguicolors = true

-- Editor
opt.number = true
opt.wrap = false
opt.signcolumn = 'yes'
opt.showmatch = true
opt.showmode = false
opt.foldmethod = 'marker'
opt.splitright = true
opt.splitbelow = true
opt.conceallevel = 0
opt.colorcolumn = '80'
opt.cursorline = true
opt.scrolloff = 10
opt.expandtab = true
opt.shiftwidth = 2
opt.tabstop = 2
opt.smartindent = true
opt.shortmess:append {c = true}
```

### lua/keymaps.lua
Concentra os atalhos gerais e da maioria dos plugins. Existem casos, como o lsp, que os *mappings* são adicionados no `on_attach` no arquivo de configuração do lsp.

```lua
local set = vim.api.nvim_set_keymap
local ns = { noremap = true, silent = true }

-- Command
set("n", ";", ":", { noremap = true })

-- Clean Search
set("n", "<Leader><Space>", ":let @/=''<CR>", ns)

-- Window
set("n", "<C-j>", ":resize -2<CR>", ns)
set("n", "<C-k>", ":resize +2<CR>", ns)
set("n", "<C-h>", ":vertical resize -2<CR>", ns)
set("n", "<C-l>", ":vertical resize +2<CR>", ns)
set("n", "<Leader>h", ":<C-u>split<CR>", ns)
set("n", "<Leader>v", ":<C-u>vsplit<CR>", ns)

-- Moving
set("n", "j", "gj", ns)
set("n", "k", "gk", ns)

...
```

## Plugins
Pra começar, vamos criar um arquivo **lua/plugins/paq.lua** e adicionar **paq-nvim** e o [nvim-lua/plenary.vim](https://github.com/nvim-lua/plenary.nvim) que é requisito para o funcionamento de outros plugins:

```lua
require('paq') {
  'savq/paq-nvim';
  'nvim-lua/plenary.nvim';
}
```

Adicionamos o arquivo no init.lua:

```lua
...
-- Plugins
require 'plugins.paq'
...
```

`:luafile %` para atualizar o nvim e os comandos `:PaqInstall` e `:PaqSync` estarão lá.

A seguir, separei alguns plugins como sugestão:

### Editor
Para melhorar a experiência com o editor eu sugiro:

```lua
...
  -- Editor
  'windwp/nvim-autopairs';
  'tpope/vim-surround';
  'tpope/vim-commentary';
  'tpope/vim-repeat';
  'pbrisbin/vim-mkdir';
  'RRethy/vim-illuminate';
...
```

### Visual
Para deixar seu nvim com um visual mais interessante:

```lua
...
  -- Visual
  'glepnir/dashboard-nvim';
  'TaDaa/vimade';
  'famiu/feline.nvim';
  'kyazdani42/nvim-web-devicons';
  'kyazdani42/nvim-tree.lua';
  'nvim-telescope/telescope.nvim';
  'akinsho/bufferline.nvim';
  'Yggdroot/indentLine';
  'nvim-treesitter/nvim-treesitter';
...
```

<!--
O próximo passo é adicionar os plugins referente as linguagens que você utiliza.

As minhas atuais:
- NeoVim para Flutter
- NeoVim para Javascript / Typescript
-->

## Lsp: Install e Config
Com os plugins [neovim/nvim-lspconfig](https://github.com/neovim/nvim-lspconfig) e [williamboman/nvim-lsp-installer](https://github.com/williamboman/nvim-lsp-installer) vamos configurar e instalar os servers de cada linguagem.

Para que algum servidor comece a funcionar é necessário que ele seja instalado e inicializado, a maneira mais fácil de fazer isso é buscando todas instaladas:

### lua/plugins/lsp-config.lua
```lua
local lsp_installer = require("nvim-lsp-installer")
lsp_installer.on_server_ready(function (server) server:setup {} end)
```

Para instalar:
`:LspInstall <server>` ou `:LspInstallInfo` e navegue nos servidores da lista pressionando `i` para instalar. Com `:LspInfo` você consegue ver o nome dos servidores (para adicionar ao setup).

Para os atalhos funcionarem, vamos adicionar a função `on_attach` no setup do lspconfig:

```lua
local ns = { noremap = true, silent = true }
local on_attach = function(_, bufnr)
  local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
  local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end

  buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')
  buf_set_keymap('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<CR>', ns)
  buf_set_keymap('n', 'gf', '<cmd>lua vim.lsp.buf.definition()<CR>', ns)
  buf_set_keymap('n', 'K', '<cmd>lua vim.lsp.buf.hover()<CR>', ns)
  buf_set_keymap('n', '<C-k>', '<cmd>lua vim.lsp.buf.signature_help()<CR>', ns)
  buf_set_keymap('n', '<space>wa', '<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>', ns)
  buf_set_keymap('n', '<space>wr', '<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>', ns)
  buf_set_keymap('n', '<space>wl', '<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>', ns)
  buf_set_keymap('n', '<space>rn', '<cmd>lua vim.lsp.buf.rename()<CR>', ns)
  buf_set_keymap('n', '<space>ca', '<cmd>lua vim.lsp.buf.code_action()<CR>', ns)
  buf_set_keymap('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', ns)
  buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', ns)
  buf_set_keymap('n', '<space>e', '<cmd>lua vim.lsp.diagnostic.show_line_diagnostics()<CR>', ns)
  buf_set_keymap('n', '[d', '<cmd>lua vim.lsp.diagnostic.goto_prev()<CR>', ns)
  buf_set_keymap('n', ']d', '<cmd>lua vim.lsp.diagnostic.goto_next()<CR>', ns)
  buf_set_keymap('n', '<space>q', '<cmd>lua vim.lsp.diagnostic.set_loclist()<CR>', ns)
  buf_set_keymap('n', '<space>f', '<cmd>lua vim.lsp.buf.formatting()<CR>', ns)
end

local lsp_installer = require("nvim-lsp-installer")
lsp_installer.on_server_ready(
  function (server)
    local opts = {
      on_attach = on_attach,
    }
    server:setup(opts)
    vim.cmd [[ do User LspAttachBuffers ]]
  end
)
```

`:h lsp` para mais informações e `:checkheath` para verificar se está tudo correto :)

## Lsp-cmp

O [lsp-cmp](https://github.com/hrsh7th/nvim-cmp) é responsável por adicionar a funcionalidade de “auto-complete”, exibindo sugestões ao digitar ou solicitar via comando/atalho.

Após instalar o plugin, precisamos adicionar a seguinte configuração no nosso lspconfig (**lua/plugins/lsp-config.lua**).

Vamos passar uma nova opção `capabilities` nas opções do server setup:

```lua
local capabilities = require'cmp_nvim_lsp'.update_capabilities(
  vim.lsp.protocol.make_client_capabilities()
)

...

local opts = {
  on_attach = on_attach,
  capabilities = capabilities,
}
...
``` 

Para o funcionamento do nvim-cmp, criei um arquivo **plugins/cmp.lua** com as seguintes configurações:

```lua
local cmp = require'cmp'

cmp.setup{
  completion = {
    completeopt ='menu,menuone,noinsert',
  },
  experimental = {
    ghost_text = true,
  },
  mapping = {
    ['<CR>'] = cmp.mapping.confirm({
      behavior = cmp.ConfirmBehavior.Replace,
      select = true,
    }),
    ['<C-d>'] = cmp.mapping.scroll_docs(-4),
    ['<C-f>'] = cmp.mapping.scroll_docs(4),
    ['<C-Space>'] = cmp.mapping.complete(),
    ['<C-e>'] = cmp.mapping.close(),
    ["<Tab>"] = cmp.select_next_item({
      behavior = cmp.SelectBehavior.Select
    }),
    ["<S-Tab>"] = cmp.select_prev_item({
      behavior = cmp.SelectBehavior.Select
    }),
  },
  sources = {
    { name = 'nvim_lsp' },
  }
}
```

Desta forma a caixa de sugestão vai aparecer sempre que você começar a digitar e é possível navegar entre as opções com o Tab/S-Tab e selecionar com o Enter.

No meu repositório pessoal, o cmp.lua esta configurado com alguns adicionais como a integração com o [LuaSnip](https://github.com/L3MON4D3/LuaSnip).

## Meu nvim-config
Você pode ver minhas configs atuais no repositório:

{% github enriquesaid/nvim-config %}