Configuração do LSP

    Definição curta: Tutorial para configurar o cliente LSP (Language Server Protocol) embutido do Neovim com vim.lsp.config e vim.lsp.enable, usando o nvim-lspconfig como fonte das configurações por servidor e o Mason para instalar os binários.

    Antes de começar

    • Neovim v0.11 ou mais recente instalado — confira com nvim --version
    • Um init.lua que já carrega, ainda que vazio

    O que você vai aprender

    • Explicar Requisitos de versão com suas palavras
    • Explicar Instalar o nvim-lspconfig com suas palavras
    • Explicar Instalar servers com Mason com suas palavras
    • Localizar o assunto desta página no :help do seu próprio Neovim

    O que é

    O Neovim traz um cliente LSP embutido. O nvim-lspconfig não é esse cliente: é uma coleção de configurações prontas — comando, tipos de arquivo e marcador de raiz — para cada servidor de linguagem.

    A forma de ligar os dois mudou. Até o Neovim 0.10 se escrevia require('lspconfig').pyright.setup({}). A partir do 0.11 existem vim.lsp.config e vim.lsp.enable no núcleo, e o require('lspconfig') passou a ser oficialmente desencorajado: hoje emite aviso e a intenção declarada é que vire erro.

    Este tutorial usa a forma atual. Se você tem uma configuração escrita no formato antigo, a seção Migrando do lspconfig.setup mostra a tradução linha a linha.

    Índice de sub-tópicos

    Requisitos de versão

    O nvim-lspconfig exige Neovim 0.11.3 ou mais recente, e o suporte ao 0.10 está declarado como algo que será removido. Confira antes de qualquer coisa:

    nvim --version | head -1

    Se aparecer 0.10 ou anterior, atualize primeiro — ver Instalação. Boa parte dos relatos de “o LSP não anexa” na internet é justamente uma versão velha combinada com um nvim-lspconfig novo.

    Instalar o nvim-lspconfig

    Com o gerenciador embutido do Neovim 0.12+:

    vim.pack.add({
      { src = "https://github.com/neovim/nvim-lspconfig" },
    })

    Com lazy.nvim:

    -- plugins/lsp.lua
    return {
      "neovim/nvim-lspconfig",
      dependencies = {
        "mason-org/mason.nvim",
        "mason-org/mason-lspconfig.nvim",
      },
    }

    Instalar servers com Mason

    O Mason baixa os binários dos servidores; ele não configura nada.

    -- setup/mason.lua
    require("mason").setup()
    require("mason-lspconfig").setup({
      ensure_installed = {
        "lua_ls",        -- Lua
        "ts_ls",         -- TypeScript/JavaScript
        "pyright",       -- Python
        "rust_analyzer", -- Rust
        "gopls",         -- Go
      },
    })

    Comando interativo: :Mason.

    Erros comuns

    • O servidor de TypeScript chama-se ts_ls. O nome antigo era tsserver, renomeado em 2024. Configuração copiada de tutorial antigo falha em silêncio: o Neovim não reclama de um nome de config que não existe, ele só não anexa nada.
    • O Mason mudou de dono. Os repositórios williamboman/mason.nvim e williamboman/mason-lspconfig.nvim hoje redirecionam para a organização mason-org. O redirecionamento funciona, mas vale corrigir o endereço no seu init.lua para não depender dele.
    • Mason instala, não configura. Instalar o pyright pelo :Mason não faz o LSP anexar; falta o vim.lsp.enable("pyright").

    Ativar e customizar servers

    Ativar é o passo mínimo. O nvim-lspconfig já traz o comando, os tipos de arquivo e o marcador de raiz de cada servidor:

    -- setup/lsp.lua
    vim.lsp.enable({ "lua_ls", "pyright", "ts_ls", "rust_analyzer", "gopls" })

    Customizar só é preciso quando você quer mudar alguma coisa:

    vim.lsp.config("lua_ls", {
      settings = {
        Lua = {
          runtime = { version = "LuaJIT" },
          diagnostics = { globals = { "vim" } },
          workspace = { library = vim.api.nvim_get_runtime_file("", true) },
        },
      },
    })

    Servidores que não estão no $PATH precisam do cmd explícito:

    vim.lsp.config("jdtls", {
      cmd = { "/caminho/para/jdtls" },
    })

    A ordem em que as configurações são lidas é: lsp/ no runtimepath, depois after/lsp/, depois as chamadas de vim.lsp.config(). A última vence.

    Keymaps LSP

    O Neovim já define atalhos padrão quando o LSP anexa — grn para renomear, gra para code action, grr para referências, K para hover. Veja :help lsp-defaults. Só redefina o que você realmente quer diferente:

    -- setup/lsp/keymaps.lua
    vim.api.nvim_create_autocmd("LspAttach", {
      callback = function(args)
        local opts = { buffer = args.buf, silent = true }
        vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts)
        vim.keymap.set("n", "gD", vim.lsp.buf.declaration, opts)
        vim.keymap.set("n", "gi", vim.lsp.buf.implementation, opts)
        vim.keymap.set("n", "<leader>rn", vim.lsp.buf.rename, opts)
        vim.keymap.set("n", "<leader>ca", vim.lsp.buf.code_action, opts)
    
        -- `vim.diagnostic.goto_prev`/`goto_next` estão descontinuados
        vim.keymap.set("n", "[d", function()
          vim.diagnostic.jump({ count = -1, float = true })
        end, opts)
        vim.keymap.set("n", "]d", function()
          vim.diagnostic.jump({ count = 1, float = true })
        end, opts)
      end,
    })

    Prender os atalhos ao evento LspAttach faz com que eles existam só nos buffers em que há servidor ativo — em vez de valerem globalmente e falharem calados no resto.

    Migrando do lspconfig.setup

    A tradução é quase mecânica:

    Antes (descontinuado)Agora
    require("lspconfig").pyright.setup({})vim.lsp.enable("pyright")
    require("lspconfig").lua_ls.setup({ settings = {...} })vim.lsp.config("lua_ls", { settings = {...} }) + vim.lsp.enable("lua_ls")
    require("lspconfig").tsserver.setup({})vim.lsp.enable("ts_ls")
    on_attach = function(...) ... end por servidorum autocomando em LspAttach
    :LspStart / :LspStop / :LspRestart:lsp enable / :lsp disable / :lsp restart
    flowchart TD
        A["Mason: instalar\no binário do servidor"] --> B["vim.lsp.config:\ncustomizar (opcional)"]
        B --> C["vim.lsp.enable:\nativar por filetype"]
        C --> D["LspAttach:\nkeymaps do buffer"]
        D --> E["vim.diagnostic:\nnavegar pelos erros"]

    Status e diagnóstico

    Texto virtual e sinais na coluna:

    vim.diagnostic.config({
      virtual_text = { prefix = "●" },
      signs = true,
      underline = true,
    })

    Para descobrir por que um servidor não anexou:

    :checkhealth vim.lsp

    :LspInfo continua funcionando como apelido desse comando. Ele mostra os servidores ativos, os configurados e o motivo de um deles não ter subido — quase sempre binário ausente no $PATH ou marcador de raiz não encontrado no projeto.

    Você aprendeu

    • Requisitos de versão
    • Instalar o nvim-lspconfig
    • Instalar servers com Mason
    • Ativar e customizar servers
    • Keymaps LSP

    Perguntas para reflexão

    1. O que Requisitos de versão resolve, e o que se perde sem isso?
    2. O que Instalar o nvim-lspconfig resolve, e o que se perde sem isso?
    3. O que Instalar servers com Mason resolve, e o que se perde sem isso?
    4. Qual parte desta página você conseguiria reproduzir sem consultar, direto no editor?

    Artigos relacionados

    Veja também

    Referências

    • nvim-lspconfig — coleção de configurações por servidor; o README traz as instruções de migração citadas aqui
    • Mason — instalador de servidores, formatadores e linters
    • :help lsp — documentação oficial do cliente LSP embutido
    • :help lsp-configvim.lsp.config e vim.lsp.enable
    • :help diagnostic — API de diagnósticos