So far if LSP declarations in 'core/languages.lua' were duplicated (e.g. the 'astro' filetype and the 'vue' filetype both declare the 'typescript' lsp), one would simply overwrite the other. That is fine as long as there is no custom setup, but if there is one of them is lost. This commit changes it so that the different configurations extend each other. The 'latter' one still overwrites the former but this is just what must happen if there should be conflicting setups. May increase loading time slightly.
288 lines
9.1 KiB
Lua
288 lines
9.1 KiB
Lua
local servers = {}
|
|
for _, lang in pairs(Languages) do
|
|
if not lang.lsp then
|
|
goto continue
|
|
end
|
|
for name, conf in pairs(lang.lsp) do
|
|
servers[name] = vim.tbl_deep_extend("force", servers[name] or {}, conf)
|
|
end
|
|
::continue::
|
|
end
|
|
|
|
local lsp = {
|
|
{ -- pretty lsp 'peek' menus
|
|
"DNLHC/glance.nvim",
|
|
opts = { border = { enable = true }, theme = { enable = true, mode = "auto" } },
|
|
cmd = { "Glance" },
|
|
},
|
|
{
|
|
"neovim/nvim-lspconfig",
|
|
dependencies = {
|
|
{
|
|
"williamboman/mason-lspconfig.nvim",
|
|
opts = { automatic_installation = true },
|
|
dependencies = { "williamboman/mason.nvim" },
|
|
cmd = { "LspInstall", "LspUninstall" },
|
|
},
|
|
{ "saghen/blink.cmp", optional = true },
|
|
},
|
|
event = { "BufReadPost", "BufNewFile", "BufWritePre" },
|
|
opts = { servers = servers },
|
|
config = function(_, lspconfig_opts)
|
|
-- Display diagnostics as virtual text only if not in insert mode
|
|
-- /r/neovim/comments/12inp4c/disable_diagnostics_virtual_text_when_in_insert/jqqifwk/
|
|
vim.diagnostic.config({ virtual_text = true })
|
|
vim.api.nvim_create_autocmd("InsertEnter", {
|
|
callback = function()
|
|
vim.diagnostic.config({ virtual_text = false })
|
|
end,
|
|
})
|
|
vim.api.nvim_create_autocmd("InsertLeave", {
|
|
callback = function()
|
|
vim.diagnostic.config({ virtual_text = true })
|
|
end,
|
|
})
|
|
|
|
vim.fn.sign_define("DiagnosticSignError", { text = "✘", texthl = "DiagnosticSignError" })
|
|
vim.fn.sign_define("DiagnosticSignWarn", { text = "", texthl = "DiagnosticSignWarn" })
|
|
vim.fn.sign_define("DiagnosticSignInfo", { text = "", texthl = "DiagnosticSignInfo" })
|
|
vim.fn.sign_define("DiagnosticSignHint", { text = "", texthl = "DiagnosticSignHint" })
|
|
|
|
local function register(server_name, config)
|
|
if vim.fn.has("nvim-0.11") == 1 then
|
|
vim.lsp.config(server_name, config)
|
|
else
|
|
require("lspconfig")[server_name].setup(config)
|
|
end
|
|
end
|
|
|
|
for server_name, config in pairs(lspconfig_opts.servers) do
|
|
register(server_name, config)
|
|
if vim.fn.has("nvim-0.11") == 0 then
|
|
config.capabilities = require("blink.cmp").get_lsp_capabilities(config.capabilities)
|
|
end
|
|
end
|
|
|
|
register("marksman", {
|
|
filetypes = { "markdown", "quarto" },
|
|
on_attach = function(client, _)
|
|
-- TODO: for some reason this stays true even after rootdir switch?
|
|
if client.config.in_zk_notebook then
|
|
local default_handler = vim.diagnostic.handlers.virtual_text
|
|
vim.diagnostic.handlers.virtual_text = {
|
|
show = function(namespace, bufnrr, diagnostics, opts)
|
|
for i, diagnostic in ipairs(diagnostics) do
|
|
if
|
|
diagnostic.source
|
|
== "Marksman" -- You need to check what the correct value should be here
|
|
then
|
|
table.remove(diagnostics, i)
|
|
end
|
|
end
|
|
default_handler.show(namespace, bufnrr, diagnostics, opts)
|
|
end,
|
|
hide = function(...)
|
|
default_handler.hide(...)
|
|
end,
|
|
}
|
|
default_handler = vim.diagnostic.handlers.signs
|
|
vim.diagnostic.handlers.signs = {
|
|
show = function(namespace, bufnrr, diagnostics, opts)
|
|
for i, diagnostic in ipairs(diagnostics) do
|
|
if
|
|
diagnostic.source
|
|
== "Marksman" -- You need to check what the correct value should be here
|
|
then
|
|
table.remove(diagnostics, i)
|
|
end
|
|
end
|
|
default_handler.show(namespace, bufnrr, diagnostics, opts)
|
|
end,
|
|
hide = function(...)
|
|
default_handler.hide(...)
|
|
end,
|
|
}
|
|
end
|
|
end,
|
|
on_new_config = function(conf, new_root)
|
|
if require("lspconfig.util").root_pattern(".zk")(new_root) then
|
|
conf.in_zk_notebook = true
|
|
else
|
|
conf.in_zk_notebook = false
|
|
end
|
|
end,
|
|
})
|
|
|
|
local python_path
|
|
-- ensure python virtualenv is determined automatically on lsp start
|
|
-- we primarily use pyright for cmp lsp completion & hover info
|
|
register("basedpyright", {
|
|
on_attach = function(client, _)
|
|
require("core.util").set_python_env()
|
|
if python_path == nil then
|
|
python_path, _ = vim.fn.expand(require("core.util").get_python_venv_bin(client.config.root_dir))
|
|
end
|
|
client.config.settings.python = {} or client.config.settings.python
|
|
client.config.settings.python.pythonPath = python_path
|
|
end,
|
|
settings = {
|
|
-- disable imports and linting since, using ruff for it
|
|
pyright = {
|
|
disableOrganizeImports = true,
|
|
},
|
|
python = {
|
|
analysis = {
|
|
-- ignore all files, use ruff for linting
|
|
ignore = { "*" },
|
|
},
|
|
},
|
|
},
|
|
})
|
|
register("ruff", {
|
|
on_attach = function(client, _)
|
|
require("core.util").set_python_env()
|
|
client.server_capabilities.hoverProvider = false -- we use pyright for hover info
|
|
if python_path == nil then
|
|
python_path, _ = vim.fn.expand(require("core.util").get_python_venv_bin(client.config.root_dir))
|
|
end
|
|
client.config.settings.python = {} or client.config.settings.python
|
|
client.config.settings.python.pythonPath = python_path
|
|
end,
|
|
})
|
|
|
|
-- set up arduino with the help of arduino.nvim plugin
|
|
if require("core.util").is_available("arduino") then
|
|
register("arduino_language_server", {
|
|
on_new_config = require("arduino").on_new_config,
|
|
})
|
|
end
|
|
|
|
-- attach ltex for fitting ft only when spell checking becomes enabled
|
|
vim.api.nvim_create_autocmd("User", {
|
|
pattern = "SpellEnable",
|
|
callback = function()
|
|
register("ltex", {
|
|
on_attach = function(_, _)
|
|
if require("core.util").is_available("ltex_extra") then
|
|
require("ltex_extra").setup()
|
|
end
|
|
end,
|
|
settings = {
|
|
ltex = {
|
|
language = vim.o.spelllang,
|
|
},
|
|
},
|
|
})
|
|
vim.cmd("LspStart ltex")
|
|
end,
|
|
})
|
|
end,
|
|
keys = { { "<leader>vs", ":LspInfo<cr>", desc = "LspInfo" } },
|
|
},
|
|
}
|
|
|
|
vim.api.nvim_create_autocmd("LspAttach", {
|
|
desc = "LSP actions",
|
|
callback = function(event)
|
|
local o = function(add_opts)
|
|
return vim.tbl_extend("force", { buffer = event.buf }, add_opts)
|
|
end
|
|
|
|
local map = vim.keymap.set
|
|
map("n", "K", "<cmd>lua vim.lsp.buf.hover()<cr>", o({ desc = "Hover definition" }))
|
|
map("n", "[d", "<cmd>lua vim.diagnostic.goto_prev()<cr>", o({ desc = "Previous diagnostic" }))
|
|
map("n", "]d", "<cmd>lua vim.diagnostic.goto_next()<cr>", o({ desc = "Next diagnostic" }))
|
|
map(
|
|
"n",
|
|
"[D",
|
|
"<cmd>lua vim.diagnostic.goto_prev({severity = vim.diagnostic.severity.ERROR})<cr>",
|
|
o({ desc = "Previous error" })
|
|
)
|
|
map(
|
|
"n",
|
|
"]D",
|
|
"<cmd>lua vim.diagnostic.goto_next({severity = vim.diagnostic.severity.ERROR})<cr>",
|
|
o({ desc = "Next error" })
|
|
)
|
|
|
|
if require("core.util").is_available("which-key") then
|
|
require("which-key").add({ "<localleader>l", group = "language" })
|
|
end
|
|
map("n", "<localleader>ld", "<cmd>lua vim.diagnostic.open_float()<cr>", o({ desc = "Show line diagnostics" }))
|
|
map("n", "<localleader>la", "<cmd>lua vim.lsp.buf.code_action()<cr>", o({ desc = "Codeactions" }))
|
|
map("n", "<localleader>ln", "<cmd>lua vim.lsp.buf.rename()<cr>", o({ desc = "Rename element" }))
|
|
map("n", "<localleader>lc", "<cmd>lua vim.lsp.buf.declaration()<cr>", o({ desc = "Declaration" }))
|
|
map("n", "<localleader>ls", "<cmd>lua vim.lsp.buf.signature_help()<cr>", o({ desc = "Signature help" }))
|
|
|
|
map("n", "<localleader>lI", function()
|
|
vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled())
|
|
end, o({ desc = "Toggle inlay hints" }))
|
|
map("n", "<localleader>lD", function()
|
|
vim.diagnostic.enable(not vim.diagnostic.is_enabled())
|
|
end, o({ desc = "Toggle Diagnostics" }))
|
|
-- FIXME: Will be re-enabled with insert-mode autocmd above
|
|
map("n", "<localleader>lo", function()
|
|
local c = vim.diagnostic.config() or {}
|
|
vim.diagnostic.config({ virtual_text = not c["virtual_text"] })
|
|
end, o({ desc = "Toggle virtual diag text" }))
|
|
if vim.fn.has("nvim-0.11") == true then -- new feature https://gpanders.com/blog/whats-new-in-neovim-0-11/#virtual-lines
|
|
map("n", "<localleader>lO", function()
|
|
local c = vim.diagnostic.config() or {}
|
|
vim.diagnostic.config({ virtual_lines = not c["virtual_lines"] })
|
|
end, o({ desc = "Toggle virtual diag lines" }))
|
|
end
|
|
|
|
local pref = function(glances, telescope, fallback)
|
|
if glances and vim.fn.exists(":Glance") > 0 then
|
|
return glances
|
|
elseif telescope and vim.fn.exists(":Telescope") > 0 then
|
|
return telescope
|
|
else
|
|
return fallback
|
|
end
|
|
end
|
|
|
|
map(
|
|
"n",
|
|
"<localleader>lr",
|
|
pref(
|
|
"<cmd>Glance references<cr>",
|
|
"<cmd>Telescope lsp_references<cr>",
|
|
"<cmd>lua vim.lsp.buf.references()<cr>"
|
|
),
|
|
o({ desc = "References" })
|
|
)
|
|
map(
|
|
"n",
|
|
"<localleader>lf",
|
|
pref(
|
|
"<cmd>Glance definitions<cr>",
|
|
"<cmd>Telescope lsp_definitions<cr>",
|
|
"<cmd>lua vim.lsp.buf.definition()<cr>"
|
|
),
|
|
o({ desc = "Definition" })
|
|
)
|
|
map(
|
|
"n",
|
|
"<localleader>lt",
|
|
pref(
|
|
"<cmd>Glance type_definitions<cr>",
|
|
"<cmd>Telescope lsp_type_definitions<cr>",
|
|
"<cmd>lua vim.lsp.buf.type_definition()<cr>"
|
|
),
|
|
o({ desc = "Type definition" })
|
|
)
|
|
map(
|
|
"n",
|
|
"<localleader>lm",
|
|
pref(
|
|
"<cmd>Glance implementations<cr>",
|
|
"<cmd>Telescope lsp_implementations<cr>",
|
|
"<cmd>lua vim.lsp.buf.implementation()<cr>"
|
|
),
|
|
o({ desc = "Implementation" })
|
|
)
|
|
end,
|
|
})
|
|
|
|
return lsp
|