LSP
Blak is built on Neovim 0.12’s native LSP API. Servers are configured with vim.lsp.config() and Mason-backed servers are enabled through mason-lspconfig’s vim.lsp.enable() integration. There is no lspconfig.setup() wrapper call anywhere in the codebase.
The native plumbing lives in lua/blak/plugins/lsp.lua. LSP keymaps are bound on LspAttach in lua/blak/core/keymaps.lua.
The flow
- Blak collects servers from
lsp.serversin the merged config (defaults +user.lua+ extras). - For each server, it calls
vim.lsp.config(name, settings)to register the config. mason-lspconfigensures Mason-backed server binaries are installed.- If
lsp.automatic_enableis true (default),mason-lspconfigcallsvim.lsp.enable(name)for installed Mason-backed servers. - When a buffer matches, Neovim auto-attaches the server and fires
LspAttach. - Blak’s
LspAttachautocmd binds the buffer-local LSP keymaps.
Default servers
Only one server ships by default — lua_ls, since Blak itself is Lua.
lsp = { servers = { lua_ls = { settings = { Lua = { runtime = { version = "LuaJIT" }, diagnostics = { globals = { "vim" } }, workspace = { checkThirdParty = false, }, telemetry = { enable = false }, }, }, }, },}Blak injects lua_ls.settings.Lua.workspace.library lazily when LSP setup runs, so config startup does not scan the full runtime path. Set workspace.library yourself if you want to replace that generated library.
Other servers ship via language extras: ts_ls, tsgo, eslint, pyright, basedpyright, ruff, rust_analyzer, taplo, gopls, marksman.
For TypeScript, use either lang.typescript for the stable ts_ls path or lang.typescript-tsgo for the experimental native tsgo language server.
For Python, use lang.python for the basic Pyright path or lang.python-pro for BasedPyright plus Ruff’s native language server.
Adding a server
In your user.lua:
return { lsp = { servers = { zls = { settings = { zls = { enable_inlay_hints = true } }, }, }, }, mason = { ensure_installed = { "zls" }, -- if Mason knows it },}Or as an extra — see Writing an extra.
If a server is installed outside Mason and you still want it enabled automatically, register it in user.lua and call vim.lsp.enable("server_name") from a User BlakReady autocmd.
Diagnostics
The default diagnostic UI:
diagnostics = { virtual_text = { spacing = 2, source = "if_many" }, virtual_lines = false, signs = true, underline = true, update_in_insert = false, severity_sort = true, float = { border = "rounded", source = "if_many" },}Override anything you want in user.lua:
return { lsp = { diagnostics = { virtual_text = false, virtual_lines = true, -- multi-line block under each diagnostic }, },}LSP keymaps
Bound on LspAttach so they’re only available when a server is attached:
| Mapping | Action |
|---|---|
gd | Definition |
gD | Declaration |
gI | Implementation |
gr | References |
K | Hover |
<leader>ca | Code action |
<leader>cr | Rename |
<leader>cf | Format |
<leader>cs | Document symbols (picker) |
<leader>cS | Workspace symbols (picker) |
Disabling automatic enable
return { lsp = { automatic_enable = false },}Then call vim.lsp.enable("server_name") yourself when you want to start it.
Inspecting what’s running
:lua = vim.lsp.get_clients() " all active clients:lua = vim.lsp.config.lua_ls " the config you registered:checkhealth vim.lsp " native health checksOn Neovim nightly
Blak supports stable and nightly. Nightly changes to vim.lsp.config() or vim.lsp.enable() can cause loud errors after a Neovim upgrade. The mitigation:
- Upgrade Neovim.
:BlakUpdateto pick up any compatibility fixes.- If something breaks,
:BlakRollbackand report.