Aprenda a configurar o LanguageServer no NeoVim
O que é Language Server?
Essa é a definição em tradução livre do próprio site provido pela Microsoft.
O Language Server Protocol (LSP) define o protocolo usado entre um editor ou IDE e um servidor de linguagem que fornece recursos de linguagem como autocompletar, ir para definição, encontrar todas as referências etc. O objetivo do Language Server Index Format (LSIF, pronunciado como "else if") é para dar suporte à navegação de código avançado em ferramentas de desenvolvimento ou uma interface do usuário da Web sem precisar de uma cópia local do código-fonte.
Em termos simples, ela é parte do que está debaixo do capô do VSCode.
Algumas considerações
Nesse artigo, eu vou compartilhar como é a minha atual configuração, utilizando a linguagem lua com o lsp do próprio NeoVim. Existem outras maneiras também, como por exemplo o famoso coc.nvim. Não seria muito bom falar sobre os dois métodos em um único post pois ficaria confuso, mas caso você se interesse, pode conferir minha configuração antiga aqui, onde eu usava essa segunda forma.
Instalação dos plugins
Esses são os plugins que eu uso para toda a questão de language server e auto complete, usando o packer.nvim como gerenciador.
-- Parsers e language servers
use 'neovim/nvim-lspconfig' -- Collection of configurations for built-in LSP client
use 'hrsh7th/nvim-cmp' -- Autocompletion plugin
use 'hrsh7th/cmp-nvim-lsp' -- LSP source for nvim-cmp
use 'saadparwaiz1/cmp_luasnip' -- Snippets source for nvim-cmp
use 'L3MON4D3/LuaSnip' -- Snippets plugin
use 'hrsh7th/cmp-buffer' -- Suporte ao Buffer no autocomplete
Instalação do servidor de linguagem
Aqui eu vou focar no servidor de linguagem do TypeScript, mas existem vários outros, que você pode conferir no repositório oficial.
tsserver
https://github.com/theia-ide/typescript-language-server
typescript-language-server
depende de typescript
. Ambos os pacotes podem ser instalados via npm
:
npm install -g typescript typescript-language-server
Para configurar o servidor de linguagens, adicione um tsconfig.json
ou jsconfig.json
para a raiz do seu projeto.
Aqui está um exemplo que desativa a verificação de tipo em arquivos JavaScript.
{
"compilerOptions": {
"module": "commonjs",
"alvo": "es6",
"checkJs": false
},
"excluir": [
"node_modules"
]
}
Snippet para ativar o servidor de linguagens:
require'lspconfig'.tsserver.setup{}
Valores padrão:
cmd
:
{ "typescript-language-server", "--stdio" }
tipos de arquivo
:
{ "javascript", "javascriptreact", "javascript.jsx", "typescript", "typescriptreact", "typescript.tsx" }
init_options
:
{
hostInfo = "neovim"
}
dir_raiz
:
root_pattern("package.json", "tsconfig.json", "jsconfig.json", ".git")
Configuração
-- Mappings.
-- See `:help vim.diagnostic.*` for documentation on any of the below functions
local opts = { noremap=true, silent=true }
vim.keymap.set('n', '<space>e', vim.diagnostic.open_float, opts)
vim.keymap.set('n', '<space>q', vim.diagnostic.setloclist, opts)
vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, opts)
vim.keymap.set('n', ']d', vim.diagnostic.goto_next, opts)
-- Use an on_attach function to only map the following keys
-- after the language server attaches to the current buffer
local on_attach = function(client, bufnr)
-- Enable completion triggered by <c-x><c-o>
vim.api.nvim_buf_set_option(bufnr, 'omnifunc', 'v:lua.vim.lsp.omnifunc')
-- Mappings.
-- See `:help vim.lsp.*` for documentation on any of the below functions
local bufopts = { noremap=true, silent=true, buffer=bufnr }
vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, bufopts)
vim.keymap.set('n', 'gd', vim.lsp.buf.definition, bufopts)
vim.keymap.set('n', 'gtd', vim.lsp.buf.type_definition, bufopts)
vim.keymap.set('n', 'gr', vim.lsp.buf.references, bufopts)
vim.keymap.set('n', 'K', vim.lsp.buf.hover, bufopts)
-- vim.keymap.set('n', '<C-k>', vim.lsp.buf.signature_help, bufopts)
vim.keymap.set('n', '<space>rn', vim.lsp.buf.rename, bufopts)
vim.keymap.set('n', '<space>fd', vim.lsp.buf.formatting, bufopts)
end
local lspconfig = require('lspconfig')
local util = require "lspconfig/util"
-- Add additional capabilities supported by nvim-cmp
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities = require('cmp_nvim_lsp').update_capabilities(capabilities)
-- Language servers
lspconfig.tsserver.setup {
on_attach = on_attach,
capabilities = capabilities,
root_dir = util.root_pattern("package.json"),
}
lspconfig.denols.setup {
on_attach = on_attach,
root_dir = util.root_pattern("deno.json", "deno.jsonc"),
}
lspconfig.cssls.setup {
capabilities = capabilities,
capabilities = capabilities,
root_dir = util.root_pattern("package.json"),
}
-- nvim-cmp setup
local cmp = require 'cmp'
local luasnip = require 'luasnip'
cmp.setup {
snippet = {
expand = function(args)
luasnip.lsp_expand(args.body)
end,
},
mapping = cmp.mapping.preset.insert({
['<C-d>'] = cmp.mapping.scroll_docs(-4),
['<C-f>'] = cmp.mapping.scroll_docs(4),
['<C-Space>'] = cmp.mapping.complete(),
['<CR>'] = cmp.mapping.confirm {
behavior = cmp.ConfirmBehavior.Replace,
select = true,
},
['<Tab>'] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_next_item()
elseif luasnip.expand_or_jumpable() then
luasnip.expand_or_jump()
else
fallback()
end
end, { 'i', 's' }),
['<S-Tab>'] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_prev_item()
elseif luasnip.jumpable(-1) then
luasnip.jump(-1)
else
fallback()
end
end, { 'i', 's' }),
}),
sources = {
{ name = 'nvim_lsp' },
{ name = 'buffer' },
{ name = 'luasnip' }
},
}
vim.diagnostic.config({
virtual_text = false,
signs = true,
underline = true,
update_in_insert = true,
severity_sort = false,
})
local signs = { Error = "", Warn = " ", Hint = " ", Info = " " }
for type, icon in pairs(signs) do
local hl = "DiagnosticSign" .. type
vim.fn.sign_define(hl, { text = icon, texthl = hl, numhl = hl })
end
Atalhos
Esses são os atalhos que eu mais uso e que estão configurados no trecho acima.
<space>e
- Mostra o resumo do erro em uma janela flutuante;]d
- Vai para o proximo diagnóstico de erro;[d
- Vai para o diagnóstico de erro anterior;gd
- Vai para a definição (comoctrl + click
no VSCode);gr
- Mostra a lista de referências da variável sob o cursor;K
- Mostra detalhes de algo (como ao hover do VSCode);<space>rn
- Renomeia uma variável;ctrl + <space>
- Mostra a lista de opções do autocomplete.