updated lsp to default to mason

This commit is contained in:
Walter Jenkins 2025-11-14 13:28:15 -06:00
parent 4564d7093e
commit 80b5d665fe
3 changed files with 142 additions and 201 deletions

View file

@ -2,162 +2,75 @@
return {
{
"neovim/nvim-lspconfig",
lazy = false,
config = function()
local lspconfig = require("lspconfig")
local util = require("lspconfig.util")
local configs = require("lspconfig.configs")
-- Recognize .templ files
vim.filetype.add({ extension = { templ = "templ" } })
-- ==============================
-- gopls
-- ==============================
lspconfig.gopls.setup({
root_dir = function(fname)
return util.root_pattern("go.work", "go.mod", ".git")(fname)
or util.path.dirname(fname)
end,
handlers = {
["textDocument/signatureHelp"] = function(err, result, ctx, config)
if err and err.message and err.message:find("cannot get type") then
return
end
return vim.lsp.handlers["textDocument/signatureHelp"](err, result, ctx, config)
end,
},
settings = {
gopls = {
gofumpt = true,
codelenses = {
gc_details = false,
generate = true,
regenerate_cgo = true,
run_govulncheck = true,
test = true,
tidy = true,
upgrade_dependency = true,
vendor = true,
},
hints = {
assignVariableTypes = true,
compositeLiteralFields = true,
compositeLiteralTypes = true,
constantValues = true,
functionTypeParameters = true,
parameterNames = true,
rangeVariableTypes = true,
},
analyses = {
fieldalignment = true,
nilness = true,
unusedparams = true,
unusedwrite = true,
useany = true,
},
usePlaceholders = true,
completeUnimported = true,
staticcheck = true,
directoryFilters = {
"-.git","-.vscode","-.idea","-.vscode-test","-node_modules",
"-dist","-build","-out","-coverage","-tmp","-.cache",
},
semanticTokens = true,
memoryMode = "DegradeClosed",
symbolMatcher = "FastFuzzy",
["ui.completion.experimentalPostfixCompletions"] = false,
},
},
})
-- ==============================
-- TypeScript / JavaScript (ts_ls OR tsserver fallback)
-- ==============================
local ts_server = lspconfig.ts_ls or lspconfig.tsserver
if ts_server then
ts_server.setup({})
end
-- ==============================
-- Astro (guard if missing)
-- ==============================
if lspconfig.astro then
local function get_typescript_lib()
local mason_ts = vim.fs.normalize(
"~/.local/share/nvim/mason/packages/typescript-language-server/node_modules/typescript/lib"
)
if vim.fn.isdirectory(mason_ts) == 1 then return mason_ts end
local global_ts = (vim.fn.system("npm root -g"):gsub("\n", "")) .. "/typescript/lib"
if vim.fn.isdirectory(global_ts) == 1 then return global_ts end
return vim.fs.normalize(
"~/.local/share/nvim/mason/packages/astro-language-server/node_modules/typescript/lib"
)
end
lspconfig.astro.setup({
init_options = { typescript = { tsdk = get_typescript_lib() } },
})
end
-- ==============================
-- templ (register config if missing)
-- ==============================
if not configs.templ then
configs.templ = {
default_config = {
cmd = { "templ", "lsp" },
filetypes = { "templ" },
root_dir = util.root_pattern("go.mod", ".git"),
single_file_support = true,
},
}
end
lspconfig.templ.setup({})
-- ==============================
-- Utilities
-- ==============================
---------------------------------------------------------------------------
-- LSP client utilities
---------------------------------------------------------------------------
vim.api.nvim_create_user_command("LspClients", function()
-- new API: vim.lsp.get_clients
local clients = vim.lsp.get_clients()
local counts = {}
for _, c in ipairs(clients) do
counts[c.name] = (counts[c.name] or 0) + 1
local client_counts = {}
for _, client in ipairs(clients) do
client_counts[client.name] = (client_counts[client.name] or 0) + 1
end
print("=== Active LSP Clients ===")
for name, n in pairs(counts) do
local dup = n > 1 and " ⚠️ DUPLICATE" or ""
print(string.format("%s: %d client(s)%s", name, n, dup))
for name, count in pairs(client_counts) do
local status = count > 1 and " ⚠️ DUPLICATE" or ""
print(string.format("%s: %d client(s)%s", name, count, status))
end
if next(counts) == nil then print("No active LSP clients") end
end, {})
if next(client_counts) == nil then
print("No active LSP clients")
end
end, { desc = "Show active LSP clients and detect duplicates" })
vim.api.nvim_create_user_command("LspKillDuplicates", function()
-- only worry about duplicate gopls, since thats your main concern
local gopls_clients = vim.lsp.get_clients({ name = "gopls" })
if #gopls_clients <= 1 then
print("No duplicate gopls clients found")
return
end
local keep, kill = nil, {}
for _, c in ipairs(gopls_clients) do
local cnt = 0
if c.config.settings and c.config.settings.gopls then
for _ in pairs(c.config.settings.gopls) do cnt = cnt + 1 end
end
if cnt > 0 and not keep then keep = c else table.insert(kill, c) end
end
for _, c in ipairs(kill) do
print(("Killing duplicate gopls client (id: %d)"):format(c.id))
c.stop(true)
end
if keep then print(("Kept gopls client (id: %d) with settings"):format(keep.id)) end
end, {})
local client_to_keep = nil
local clients_to_kill = {}
for _, client in ipairs(gopls_clients) do
local settings_count = 0
if client.config.settings and client.config.settings.gopls then
for _ in pairs(client.config.settings.gopls) do
settings_count = settings_count + 1
end
end
if settings_count > 0 and not client_to_keep then
client_to_keep = client
else
table.insert(clients_to_kill, client)
end
end
for _, client in ipairs(clients_to_kill) do
print(string.format("Killing duplicate gopls client (id: %d)", client.id))
client.stop(true)
end
if client_to_keep then
print(string.format("Kept gopls client (id: %d) with settings", client_to_keep.id))
end
end, { desc = "Kill duplicate gopls clients" })
---------------------------------------------------------------------------
-- Hover safety + keymaps
---------------------------------------------------------------------------
local function has_hover(bufnr)
for _, c in pairs(vim.lsp.get_active_clients({ bufnr = bufnr })) do
if c.server_capabilities and c.server_capabilities.hoverProvider then return true end
local clients = vim.lsp.get_clients({ bufnr = bufnr })
for _, c in pairs(clients) do
if c.server_capabilities and c.server_capabilities.hoverProvider then
return true
end
end
return false
end
@ -172,11 +85,16 @@ return {
vim.keymap.set(mode, lhs, rhs, { buffer = bufnr, desc = desc })
end
-- K = hover (safe)
buf_map("n", "K", function()
if not has_hover(bufnr) then return end
if not has_hover(bufnr) then
return
end
local ok, saga_hover = pcall(require, "lspsaga.hover")
if ok and saga_hover and saga_hover.render_hover_doc then
pcall(function() saga_hover:render_hover_doc() end)
pcall(function()
saga_hover:render_hover_doc()
end)
else
pcall(vim.lsp.buf.hover)
end

View file

@ -5,33 +5,39 @@ return {
dependencies = {
"williamboman/mason.nvim",
"jay-babu/mason-null-ls.nvim",
"nvimtools/none-ls-extras.nvim", -- optional
"nvimtools/none-ls-extras.nvim", -- required for eslint_d now
},
config = function()
local null_ls = require("null-ls")
-- eslint_d now comes from none-ls-extras, NOT null_ls.builtins
local eslint_d = require("none-ls.diagnostics.eslint_d")
null_ls.setup({
sources = {
-- Go
null_ls.builtins.formatting.gofumpt,
null_ls.builtins.formatting.golines, -- optional
null_ls.builtins.diagnostics.golangci_lint, -- if installed
null_ls.builtins.formatting.golines, -- optional
null_ls.builtins.diagnostics.golangci_lint, -- if installed
-- Web (keep only what you use)
-- Web
null_ls.builtins.formatting.prettierd,
null_ls.builtins.diagnostics.eslint_d,
eslint_d,
},
})
require("mason-null-ls").setup({
ensure_installed = { "gofumpt", "golines", "golangci-lint", "prettierd", "eslint_d" },
automatic_installation = true,
-- leaving automatic_setup at default (false) so it doesn't double-register sources
})
-- (optional) format on save for Go
vim.api.nvim_create_autocmd("BufWritePre", {
pattern = "*.go",
callback = function() vim.lsp.buf.format({ async = false }) end,
callback = function()
vim.lsp.buf.format({ async = false })
end,
})
end,
}