DEV Community

Cover image for NeoVim: init.lua, built in LSP e mais
Enrique Marques Junior
Enrique Marques Junior

Posted on

NeoVim: init.lua, built in LSP e mais

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 mas pode ser qualquer outro, tipo o packer.

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.

-- Settings & Keys
require 'settings'
require 'keymaps'
Enter fullscreen mode Exit fullscreen mode

lua/settings.lua

Concentra as configurações mais básicas

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}
Enter fullscreen mode Exit fullscreen mode

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.

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)

...
Enter fullscreen mode Exit fullscreen mode

Plugins

Pra começar, vamos criar um arquivo lua/plugins/paq.lua e adicionar paq-nvim e o nvim-lua/plenary.vim que é requisito para o funcionamento de outros plugins:

require('paq') {
  'savq/paq-nvim';
  'nvim-lua/plenary.nvim';
}
Enter fullscreen mode Exit fullscreen mode

Adicionamos o arquivo no init.lua:

...
-- Plugins
require 'plugins.paq'
...
Enter fullscreen mode Exit fullscreen mode

: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:

...
  -- Editor
  'windwp/nvim-autopairs';
  'tpope/vim-surround';
  'tpope/vim-commentary';
  'tpope/vim-repeat';
  'pbrisbin/vim-mkdir';
  'RRethy/vim-illuminate';
...
Enter fullscreen mode Exit fullscreen mode

Visual

Para deixar seu nvim com um visual mais interessante:

...
  -- 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';
...
Enter fullscreen mode Exit fullscreen mode

Lsp: Install e Config

Com os plugins neovim/nvim-lspconfig e 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

local lsp_installer = require("nvim-lsp-installer")
lsp_installer.on_server_ready(function (server) server:setup {} end)
Enter fullscreen mode Exit fullscreen mode

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:

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
)
Enter fullscreen mode Exit fullscreen mode

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

Lsp-cmp

O lsp-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:

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

...

local opts = {
  on_attach = on_attach,
  capabilities = capabilities,
}
...
Enter fullscreen mode Exit fullscreen mode

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

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' },
  }
}
Enter fullscreen mode Exit fullscreen mode

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.

Meu nvim-config

Você pode ver minhas configs atuais no repositório:

nvim-config

my nvim config

requirements

color scheme

install

:PaqInstall
:PaqSync

:LspInstall lua
:LspInstall typescript
:LspInstall html
:LspInstall css

:TSInstall lua
:TSInstall javascript
:TSInstall typescript
:TSInstall json
:TSInstall html
:TSInstall css
:TSInstall yaml
:TSInstall dart
Enter fullscreen mode Exit fullscreen mode

Latest comments (3)

Collapse
 
voyeg3r profile image
Sérgio Araújo • Edited

Aqui seguem algumas sugestões de um velho vimmer que agora só usa neovim:

Uma função na qual as opções de mapeamento tem um default, caso omitidas:

-- map helper
local function map(mode, lhs, rhs, opts)
    local options = { noremap = true }
    if opts then
        options = vim.tbl_extend("force", options, opts)
    end
    vim.api.nvim_set_keymap(mode, lhs, rhs, options)
end

-- other interesting text objects
-- reference: https://www.reddit.com/r/vim/comments/adsqnx/comment/edjw792
local chars = { "_", "-", ".", ":", ",", ";", "<bar>", "/", "<bslash>", "*", "+", "%", "#", "`" }
for k, v in ipairs(chars) do
    map("x", "i" .. v, ":<C-u>norm! T" .. v .. "vt" .. v .. "<CR>")
    map("x", "a" .. v, ":<C-u>norm! F" .. v .. "vf" .. v .. "<CR>")
    map("o", "a" .. v, ":normal! va" .. v .. "<CR>")
    map("o", "i" .. v, ":normal! vi" .. v .. "<CR>")
end
-- por precaução altero o timeoutlen, que é o tempo de espera para que o nvim aplique um mapeamento:
opt.timeoutlen = 500
Enter fullscreen mode Exit fullscreen mode
-- com esse mapeamento mantenho a função original do Ctrl-l e de quebra o higlight search é boleano
map(
    "n",
    "<C-l>",
    [[ (&hls && v:hlsearch ? ':nohls' : ':set hls')."\n" <BAR> redraw<CR>]],
    { silent = true, expr = true }
)
Enter fullscreen mode Exit fullscreen mode

Aqui altero o undo break, de modo que cada vez que insiro um ponto, vírgula, exclamação etc o vim adiciona um undo break, assim se eu digitar algo do tipo: "Estou demonstrando a versatilidade do vim, e de quebra ajudando outras pessoas", se eu pressionar a tecla "u" em modo normal o desfazer só vai até a vírgula.

-- More molecular undo of text
-- map("i", ",", ",<c-g>u")
map("i", ".", ".<c-g>u")
map("i", "!", "!<c-g>u")
map("i", "?", "?<c-g>u")
map("i", ";", ";<c-g>u")
map("i", ":", ":<c-g>u")
map("i", "]", "]<c-g>u")
map("i", "}", "}<c-g>u")
Enter fullscreen mode Exit fullscreen mode
Collapse
 
enrsaid profile image
Enrique Marques Junior

Perfeito, certamente vou adicionar.
Muito obrigado por comentar!

Collapse
 
voyeg3r profile image
Sérgio Araújo

Henrique: Atualizei a função para mapeamentos trocando vim.api.nvim_set_keymap por vim.keymap.set e removi alguns undo breaks porque tava muito exagerado.