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

117
init.lua
View File

@ -1,92 +1,109 @@
-- ~/.config/nvim/init.lua
require 'core.options' -- Load general options
require 'core.keymaps' -- Load general keymaps
require 'core.snippets' -- Custom code snippets
-- Install package manager (lazy.nvim)
local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim'
-- Install package manager
local lazypath = vim.fn.stdpath 'data' .. '/lazy/lazy.nvim'
if not vim.loop.fs_stat(lazypath) then
vim.fn.system({
'git', 'clone', '--filter=blob:none',
vim.fn.system {
'git',
'clone',
'--filter=blob:none',
'https://github.com/folke/lazy.nvim.git',
'--branch=stable', lazypath,
})
'--branch=stable', -- latest stable release
lazypath,
}
end
vim.opt.rtp:prepend(lazypath)
-- Filetypes
vim.filetype.add({
extension = { templ = 'templ' },
extension = {
templ = "templ",
}
})
-- Theme selection (robust against unknown NVIM_THEME)
-- Import color theme based on environment variable NVIM_THEME
local default_color_scheme = 'quantum'
local env_var_nvim_theme = os.getenv('NVIM_THEME') or default_color_scheme
local env_var_nvim_theme = os.getenv 'NVIM_THEME' or default_color_scheme
-- Define a table of theme modules
local themes = {
quantum = 'plugins.themes.quantum',
nord = 'plugins.themes.nord',
onedark = 'plugins.themes.onedark',
}
local theme_module = themes[env_var_nvim_theme] or themes[default_color_scheme]
-- Plugins
-- Setup plugins
require('lazy').setup({
require(theme_module),
require(themes[env_var_nvim_theme]),
require 'core.ui',
-- Load mason early so tools are ready for LSP configs
require 'plugins.mason',
-- Core dev UX
require 'plugins.treesitter',
require 'plugins.telescope',
require 'plugins.lualine',
require 'plugins.aerial',
require 'plugins.autoformat',
require 'plugins.flash',
require 'plugins.autocompletion',
require 'plugins.bufferline',
require 'plugins.comment',
require 'plugins.conform',
require 'plugins.database',
require 'plugins.debug',
require 'plugins.gitsigns',
require 'plugins.harpoon',
require 'plugins.lazygit',
require 'plugins.lsp',
require 'plugins.lualine',
require 'plugins.none-ls',
require 'plugins.indent-blankline',
require 'plugins.neo-tree',
require 'plugins.misc',
require 'plugins.mason',
require 'plugins.snack',
require 'plugins.telescope',
require 'plugins.toggleterm',
require 'plugins.treesitter',
require 'plugins.vim-tmux-navigator',
require 'plugins.zellij',
require 'plugins.flash',
require 'plugins.comment',
require 'plugins.harpoon',
require 'plugins.gitsigns',
require 'plugins.lazygit',
require 'plugins.aerial',
require 'plugins.misc',
-- LSP & companions
require 'plugins.autocompletion',
require 'plugins.lsp',
require 'plugins.none-ls', -- none-ls/null-ls sources & setup
require 'plugins.autoformat', -- your autoformat-on-save/idle logic
-- Optional: pick one formatter stack. If you keep Conform,
-- ensure it doesn't also format Go on save to avoid double-format.
require 'plugins.conform',
-- Debugging / DB (as you had)
require 'plugins.debug',
require 'plugins.database',
}, {
ui = {
-- If you have a Nerd Font, set icons to an empty table which will use the
-- default lazy.nvim defined Nerd Font icons otherwise define a unicode icons table
icons = vim.g.have_nerd_font and {} or {
cmd = '', config = '🛠', event = '📅', ft = '📂', init = '',
keys = '🗝', plugin = '🔌', runtime = '💻', require = '🌙',
source = '📄', start = '🚀', task = '📌', lazy = '💤 ',
cmd = '',
config = '🛠',
event = '📅',
ft = '📂',
init = '',
keys = '🗝',
plugin = '🔌',
runtime = '💻',
require = '🌙',
source = '📄',
start = '🚀',
task = '📌',
lazy = '💤 ',
},
},
})
-- (Optional) tiny helper if you ever want to source a session file
-- Function to check if a file exists
local function file_exists(file)
local f = io.open(file, 'r')
if f then f:close(); return true end
if f then
f:close()
return true
else
return false
end
end
-- local session_file = '.session.vim'
-- if file_exists(session_file) then vim.cmd('source ' .. session_file) end
-- Path to the session file
local session_file = '.session.vim'
-- Check if the session file exists in the current directory
-- if file_exists(session_file) then
-- -- Source the session file
-- vim.cmd('source ' .. session_file)
-- end
-- The line beneath this is called `modeline`. See `:help modeline`
-- vim: ts=2 sts=2 sw=2 et

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,11 +5,14 @@ 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
@ -17,21 +20,24 @@ return {
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,
}