Created
July 1, 2026 20:43
-
-
Save eduardoarandah/b2a426e56e3b436c5d16549f6f4465e6 to your computer and use it in GitHub Desktop.
Useful neovim commands to control native LSP (Neovim 0.12+) :LspInfo, :LspRestart, :LspStop
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- User commands to control native LSP (Neovim 0.12+) | |
| -- Replace :LspInfo, :LspRestart, :LspStop, etc. that used to be provided by nvim-lspconfig | |
| -- | |
| -- :LspList → clients attached to the current buffer | |
| -- :LspInfo → :checkhealth vim.lsp (the official replacement for LspInfo) | |
| -- :LspLog → opens the LSP log in a new tab | |
| -- :LspStop [name] → stops clients (! to force) | |
| -- :LspStart → re-triggers autostart on the current buffer | |
| -- :LspRestart [name] → restarts clients and re-attaches the buffers | |
| -- :LspCapabilities → inspect the server's capabilities | |
| -- ── Helpers ────────────────────────────────────────────────────────── | |
| -- Target clients: by name(s) passed as args, or the ones from the current buffer | |
| local function get_target_clients(fargs) | |
| if fargs and #fargs > 0 then | |
| local clients = {} | |
| for _, name in ipairs(fargs) do | |
| vim.list_extend(clients, vim.lsp.get_clients({ name = name })) | |
| end | |
| return clients | |
| end | |
| return vim.lsp.get_clients({ bufnr = 0 }) | |
| end | |
| -- Autocomplete with names of active clients | |
| local function complete_client_names(arglead) | |
| local seen, names = {}, {} | |
| for _, client in ipairs(vim.lsp.get_clients()) do | |
| if not seen[client.name] and vim.startswith(client.name, arglead) then | |
| seen[client.name] = true | |
| table.insert(names, client.name) | |
| end | |
| end | |
| return names | |
| end | |
| -- ── :LspList ───────────────────────────────────────────────────────── | |
| vim.api.nvim_create_user_command("LspList", function() | |
| local clients = vim.lsp.get_clients({ bufnr = 0 }) | |
| if vim.tbl_isempty(clients) then | |
| vim.notify("No LSP clients attached to this buffer", vim.log.levels.WARN) | |
| return | |
| end | |
| local lines = {} | |
| for _, c in ipairs(clients) do | |
| table.insert(lines, string.format("[%d] %s", c.id, c.name)) | |
| table.insert(lines, string.format(" root: %s", c.root_dir or "(no root_dir)")) | |
| table.insert(lines, string.format(" cmd: %s", type(c.config.cmd) == "table" and table.concat(c.config.cmd, " ") or "(function)")) | |
| end | |
| vim.notify(table.concat(lines, "\n"), vim.log.levels.INFO) | |
| end, { desc = "List LSP clients attached to the current buffer" }) | |
| -- ── :LspInfo ───────────────────────────────────────────────────────── | |
| -- In 0.12 the official replacement is :checkhealth vim.lsp | |
| vim.api.nvim_create_user_command("LspInfo", function() | |
| vim.cmd("checkhealth vim.lsp") | |
| end, { desc = "LSP info (checkhealth vim.lsp)" }) | |
| -- ── :LspLog ────────────────────────────────────────────────────────── | |
| vim.api.nvim_create_user_command("LspLog", function() | |
| vim.cmd("tabnew " .. vim.fn.fnameescape(vim.lsp.get_log_path())) | |
| end, { desc = "Open the LSP log" }) | |
| -- ── :LspStop ───────────────────────────────────────────────────────── | |
| -- :LspStop → stops the clients of the current buffer | |
| -- :LspStop intelephense → stops a client by name | |
| -- :LspStop! → forces shutdown (SIGKILL) | |
| vim.api.nvim_create_user_command("LspStop", function(opts) | |
| local clients = get_target_clients(opts.fargs) | |
| if vim.tbl_isempty(clients) then | |
| vim.notify("No clients found to stop", vim.log.levels.WARN) | |
| return | |
| end | |
| for _, client in ipairs(clients) do | |
| client:stop(opts.bang) | |
| vim.notify("Stopped: " .. client.name) | |
| end | |
| end, { | |
| nargs = "*", | |
| bang = true, | |
| complete = complete_client_names, | |
| desc = "Stop LSP clients", | |
| }) | |
| -- ── :LspStart ──────────────────────────────────────────────────────── | |
| -- Re-triggers the FileType event of the current buffer, which re-executes | |
| -- autostart (works with both lspconfig and vim.lsp.enable) | |
| vim.api.nvim_create_user_command("LspStart", function() | |
| vim.api.nvim_exec_autocmds("FileType", { buffer = 0 }) | |
| vim.notify("LSP autostart re-triggered for this buffer") | |
| end, { desc = "Start LSP on the current buffer" }) | |
| -- ── :LspRestart ────────────────────────────────────────────────────── | |
| -- Saves config and buffers for each client, stops it, and after a delay | |
| -- re-starts it re-attaching the same buffers. | |
| -- Works regardless of how the client was started (lspconfig, vim.lsp.enable, etc.) | |
| vim.api.nvim_create_user_command("LspRestart", function(opts) | |
| local clients = get_target_clients(opts.fargs) | |
| if vim.tbl_isempty(clients) then | |
| vim.notify("No clients found to restart", vim.log.levels.WARN) | |
| return | |
| end | |
| local saved = {} | |
| for _, client in ipairs(clients) do | |
| table.insert(saved, { | |
| name = client.name, | |
| config = client.config, | |
| bufs = vim.lsp.get_buffers_by_client_id(client.id), | |
| }) | |
| client:stop(opts.bang) | |
| end | |
| vim.defer_fn(function() | |
| for _, item in ipairs(saved) do | |
| for _, buf in ipairs(item.bufs) do | |
| if vim.api.nvim_buf_is_valid(buf) and vim.api.nvim_buf_is_loaded(buf) then | |
| -- vim.lsp.start reuses the client if one already exists with the same config | |
| vim.lsp.start(item.config, { bufnr = buf }) | |
| end | |
| end | |
| vim.notify("Restarted: " .. item.name) | |
| end | |
| end, 500) | |
| end, { | |
| nargs = "*", | |
| bang = true, | |
| complete = complete_client_names, | |
| desc = "Restart LSP clients", | |
| }) | |
| -- ── :LspCapabilities ───────────────────────────────────────────────── | |
| -- Useful to know if the server supports formatting, inlayHints, etc. | |
| vim.api.nvim_create_user_command("LspCapabilities", function(opts) | |
| local clients = get_target_clients(opts.fargs) | |
| if vim.tbl_isempty(clients) then | |
| vim.notify("No LSP clients in this buffer", vim.log.levels.WARN) | |
| return | |
| end | |
| for _, client in ipairs(clients) do | |
| -- Opens in a scratch buffer so you can search with / | |
| local buf = vim.api.nvim_create_buf(false, true) | |
| local lines = vim.split(vim.inspect(client.server_capabilities), "\n") | |
| vim.api.nvim_buf_set_lines(buf, 0, -1, false, lines) | |
| vim.api.nvim_buf_set_name(buf, "capabilities://" .. client.name) | |
| vim.bo[buf].filetype = "lua" | |
| vim.cmd.tabnew() | |
| vim.api.nvim_win_set_buf(0, buf) | |
| end | |
| end, { | |
| nargs = "*", | |
| complete = complete_client_names, | |
| desc = "View LSP server capabilities", | |
| }) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment