Neovim lsp setup#
Basic workflow#
LSP setup is primarily done by 2 methods, as mentioned in the lsp-config docs.
vim.lsp.config("name", "config")vim.lsp.enable("name")
where name is the LSP server name.
When an LSP client starts, it resolves its configuration by merging the following sources (merge semantics) defined by vim.tbl.deep_extend, with force behaviour, in order of increasing priority.
-- Defined in init.lua
vim.lsp.config('*', {
capabilities = {
textDocument = {
semanticTokens = {
multilineTokenSupport = true,
}
}
},
root_markers = { '.git' },
})
-- Defined in <rtp>/lsp/clangd.lua
return {
cmd = { 'clangd' },
root_markers = { '.clangd', 'compile_commands.json' },
filetypes = { 'c', 'cpp' },
}
-- Defined in init.lua
vim.lsp.config('clangd', {
filetypes = { 'c' },
})
The merged result is
{
-- From the clangd configuration in <rtp>/lsp/clangd.lua
cmd = { 'clangd' },
-- From the clangd configuration in <rtp>/lsp/clangd.lua
-- Overrides the "*" configuration in init.lua
root_markers = { '.clangd', 'compile_commands.json' },
-- From the clangd configuration in init.lua
-- Overrides the clangd configuration in <rtp>/lsp/clangd.lua
filetypes = { 'c' },
-- From the "*" configuration in init.lua
capabilities = {
textDocument = {
semanticTokens = {
multilineTokenSupport = true,
}
}
}
}
Runtime flow in this config#
This repository wires LSP setup through lua/plugins/pde/lsp.lua and applies
buffer-local behavior in a single LspAttach callback.
lua/plugins/pde/lsp.lua
|-- lsp_setup()
| |-- get_server_configs()
| |-- update_server_configs(server_configs)
| |-- enable_servers(profile_config.get_enabled_lsp_servers(), server_configs)
| |-- if profile_config.enable_mason_installs()
| | `-- install_mason_packages(profile_config.get_mason_packages())
| |-- setup_lsp_keymaps()
| `-- setup_diagnostic_config()
`-- LspAttach callback
|-- setup_native_buffer_mappings(bufnr)
|-- setup_plugin_buffer_mappings(bufnr)
|-- setup_autocmds(client, bufnr)
`-- setup_clangd_extensions(bufnr) for clangd
LspAttach autocommand#
31local setup_lsp_keymaps = function()
32 vim.api.nvim_create_autocmd("LspAttach", {
33 group = vim.api.nvim_create_augroup("vvnraman.lsp.config", { clear = true }),
34 callback = function(event)
This registers the LspAttach callback entry point.
50 local client_is = function(name)
51 local client_exists = false
52 if client.server_info and name == client.server_info.name then
53 client_exists = true
54 end
55 if client.name and name == client.name then
56 client_exists = true
57 end
58
59 return client_exists
60 end
61
62 if client_is("clangd") then
63 require("plugins.pde.attach").setup_clangd_extensions(bufnr)
64 end
Inside the callback, the clangd branch applies clangd-specific extensions.
Profile-driven server and Mason policy#
195 opts = function()
196 return {
197 install_root_dir = require("vvn.profile_config").get_mason_install_root_dir(),
198 ui = {
199 icons = {
200 server_installed = "✓",
201 server_pending = "➜",
202 server_uninstalled = "✗",
203 },
204 },
205 }
206 end,
The Mason plugin reads its install root from vvn.profile_config through
get_mason_install_root_dir().