LSP Configuration

Language Server Protocol configuration, keybindings, and diagnostic workflows.

Basic LSP Setup

Minimal lspconfig configuration
local lspconfig = require('lspconfig')

lspconfig.lua_ls.setup({})
lspconfig.pyright.setup({})
lspconfig.bashls.setup({})

Common Language Servers

Servers for daily use
lspconfig.lua_ls.setup({})       -- Lua (sumneko)
lspconfig.pyright.setup({})      -- Python
lspconfig.bashls.setup({})       -- Bash/Zsh
lspconfig.jsonls.setup({})       -- JSON
lspconfig.yamlls.setup({})       -- YAML
lspconfig.gopls.setup({})        -- Go
lspconfig.rust_analyzer.setup({})  -- Rust
lspconfig.clangd.setup({})      -- C/C++
lspconfig.ts_ls.setup({})       -- TypeScript/JavaScript

The on_attach Pattern

Define keymaps when LSP attaches to a buffer
local on_attach = function(client, bufnr)
  local opts = { buffer = bufnr, noremap = true, 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', 'gr', vim.lsp.buf.references, opts)
  vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, opts)
  vim.keymap.set('n', 'K', vim.lsp.buf.hover, 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.keymap.set('n', '<leader>f', function()
    vim.lsp.buf.format({ async = true })
  end, opts)
end
Apply on_attach to all servers
lspconfig.lua_ls.setup({ on_attach = on_attach })
lspconfig.pyright.setup({ on_attach = on_attach })
lspconfig.bashls.setup({ on_attach = on_attach })

Diagnostic Navigation

Navigate and display diagnostics
vim.keymap.set('n', '[d', vim.diagnostic.goto_prev)   -- previous diagnostic
vim.keymap.set('n', ']d', vim.diagnostic.goto_next)   -- next diagnostic
vim.keymap.set('n', '<leader>e', vim.diagnostic.open_float)  -- show in float
vim.keymap.set('n', '<leader>q', vim.diagnostic.setloclist)  -- send to loclist
Configure diagnostic display
vim.diagnostic.config({
  virtual_text = true,       -- inline diagnostic text
  signs = true,              -- signs in the gutter
  underline = true,          -- underline problematic code
  update_in_insert = false,  -- don't update while typing
  severity_sort = true,      -- errors before warnings
  float = {
    border = 'rounded',
    source = true,           -- show which LSP produced the diagnostic
  },
})

Formatting

Format on save with autocommand
vim.api.nvim_create_autocmd('BufWritePre', {
  callback = function()
    vim.lsp.buf.format({ async = false })
  end,
})
Format only with specific LSP client
vim.lsp.buf.format({
  filter = function(client)
    return client.name == 'null-ls'  -- use only null-ls for formatting
  end,
})

Server-Specific Configuration

lua_ls with Neovim runtime awareness
lspconfig.lua_ls.setup({
  on_attach = on_attach,
  settings = {
    Lua = {
      runtime = { version = 'LuaJIT' },
      diagnostics = {
        globals = { 'vim' },   -- recognize vim global
      },
      workspace = {
        library = vim.api.nvim_get_runtime_file('', true),
        checkThirdParty = false,
      },
      telemetry = { enable = false },
    },
  },
})
pyright with venv detection
lspconfig.pyright.setup({
  on_attach = on_attach,
  settings = {
    python = {
      analysis = {
        typeCheckingMode = 'basic',
        autoSearchPaths = true,
        useLibraryCodeForTypes = true,
      },
    },
  },
})

Capabilities (for nvim-cmp integration)

Advertise completion capabilities to LSP servers
local capabilities = require('cmp_nvim_lsp').default_capabilities()

lspconfig.lua_ls.setup({
  on_attach = on_attach,
  capabilities = capabilities,
})

Inspecting LSP Status

Check active clients and server status
:LspInfo         " show attached LSP clients and their status
:LspLog          " open LSP log file
:LspRestart      " restart LSP clients for current buffer
:LspStop         " stop all LSP clients
:LspStart        " start LSP clients for current buffer

LSP Keybindings Summary

Standard LSP keymaps at a glance
gd             " go to definition
gD             " go to declaration
gr             " find references
gi             " go to implementation
K              " hover documentation
<leader>rn     " rename symbol
<leader>ca     " code action
<leader>f      " format buffer
[d             " previous diagnostic
]d             " next diagnostic
<leader>e      " diagnostic float
<leader>q      " diagnostics to location list