nvim/lua/plugins/lsp.lua

145 lines
4.6 KiB
Lua

return {
"neovim/nvim-lspconfig",
event = { "BufReadPre", "BufNewFile" },
config = function()
-- Load trusted project-local LSP settings from .nvim.lua.
local function load_project_lsp_settings(server_name, root_dir)
if not root_dir then
return {}
end
local config_file = root_dir .. "/.nvim.lua"
if vim.fn.filereadable(config_file) ~= 1 then
return {}
end
local contents = vim.secure.read(config_file)
if not contents then
return {}
end
local chunk, load_error = load(contents, "@" .. config_file, "t")
if not chunk then
vim.notify("Invalid project config: " .. load_error, vim.log.levels.WARN)
return {}
end
local ok, project_config = pcall(chunk)
if not ok then
vim.notify("Failed to load project config: " .. project_config, vim.log.levels.WARN)
return {}
end
if project_config and project_config.lsp and project_config.lsp[server_name] then
return project_config.lsp[server_name]
end
return {}
end
-- Setup keymaps on attach
local function setup_keymaps(bufnr)
local map = function(mode, lhs, rhs, desc)
vim.keymap.set(mode, lhs, rhs, { buffer = bufnr, silent = true, noremap = true, desc = desc })
end
map('n', 'gd', vim.lsp.buf.definition, 'LSP: Go to definition')
map('n', 'gr', vim.lsp.buf.references, 'LSP: References')
map('n', 'gD', vim.lsp.buf.declaration, 'LSP: Go to declaration')
map('n', 'gI', vim.lsp.buf.implementation, 'LSP: Go to implementation')
map('n', 'K', vim.lsp.buf.hover, 'LSP: Hover')
end
-- Global LspAttach handler to load project settings and setup keymaps
vim.api.nvim_create_autocmd('LspAttach', {
group = vim.api.nvim_create_augroup('lsp_project_settings', { clear = true }),
callback = function(args)
local client = vim.lsp.get_client_by_id(args.data.client_id)
if not client then
return
end
-- Setup keymaps for this buffer
setup_keymaps(args.buf)
if client:supports_method("textDocument/completion") then
vim.lsp.completion.enable(true, client.id, args.buf)
if vim.fn.has("nvim-0.12") == 1 then
vim.bo[args.buf].complete = "o^20"
end
end
-- Load and send project-specific settings
local project_settings = load_project_lsp_settings(client.name, client.root_dir)
if project_settings.settings then
-- Merge with existing settings
client.settings = vim.tbl_deep_extend(
"force",
client.settings or {},
project_settings.settings
)
-- Send didChangeConfiguration to update the server
vim.schedule(function()
client:notify("workspace/didChangeConfiguration", { settings = client.settings })
end)
end
end,
})
-- Configure servers using vim.lsp.config (Neovim 0.11+ API)
local function configure(server_name, opts)
opts = opts or {}
-- Configure the server using the new API
vim.lsp.config(server_name, opts)
end
-- Configure all servers
configure("lua_ls", {
settings = {
Lua = {
diagnostics = { globals = { "vim" } },
},
},
})
configure("ts_ls")
configure("html")
configure("cssls")
configure("jsonls")
configure("bashls")
configure("marksman")
configure("intelephense", {
init_options = {
storagePath = vim.fn.stdpath("cache") .. "/intelephense",
globalStoragePath = vim.fn.stdpath("data") .. "/intelephense",
},
single_file_support = false,
})
-- Python: pyright for type checking, ruff for linting/formatting
configure("pyright", {
settings = {
pyright = {
-- Only use pyright for type checking
disableOrganizeImports = true, -- Let ruff handle imports
},
python = {
analysis = {
typeCheckingMode = "basic", -- Type checking only
-- Let ruff handle style/formatting diagnostics
diagnosticSeverityOverrides = {
-- Keep type/syntax errors, warnings
-- Disable style-related diagnostics (ruff handles these)
},
},
},
},
})
configure("ruff") -- Ruff LSP for formatting + linting
-- Enable all configured servers
vim.lsp.enable({ "lua_ls", "ts_ls", "html", "cssls", "jsonls", "bashls", "marksman", "intelephense", "pyright", "ruff" })
end,
}