210 lines
6.3 KiB
Lua
210 lines
6.3 KiB
Lua
local utils = require("utils")
|
|
|
|
vim.api.nvim_create_autocmd("LspAttach", {
|
|
group = vim.api.nvim_create_augroup("lsp_buf_conf", { clear = true }),
|
|
callback = function(event_context)
|
|
local client = vim.lsp.get_client_by_id(event_context.data.client_id)
|
|
-- vim.print(client.name, client.server_capabilities)
|
|
|
|
if not client then
|
|
return
|
|
end
|
|
|
|
local bufnr = event_context.buf
|
|
|
|
-- Mappings.
|
|
local map = function(mode, l, r, opts)
|
|
opts = opts or {}
|
|
opts.silent = true
|
|
opts.buffer = bufnr
|
|
vim.keymap.set(mode, l, r, opts)
|
|
end
|
|
|
|
map("n", "gd", function()
|
|
vim.lsp.buf.definition {
|
|
on_list = function(options)
|
|
-- custom logic to avoid showing multiple definition when you use this style of code:
|
|
-- `local M.my_fn_name = function() ... end`.
|
|
-- See also post here: https://www.reddit.com/r/neovim/comments/19cvgtp/any_way_to_remove_redundant_definition_in_lua_file/
|
|
|
|
-- vim.print(options.items)
|
|
local unique_defs = {}
|
|
local def_loc_hash = {}
|
|
|
|
-- each item in options.items contain the location info for a definition provided by LSP server
|
|
for _, def_location in pairs(options.items) do
|
|
-- use filename and line number to uniquelly indentify a definition,
|
|
-- we do not expect/want multiple definition in single line!
|
|
local hash_key = def_location.filename .. def_location.lnum
|
|
|
|
if not def_loc_hash[hash_key] then
|
|
def_loc_hash[hash_key] = true
|
|
table.insert(unique_defs, def_location)
|
|
end
|
|
end
|
|
|
|
options.items = unique_defs
|
|
|
|
-- set the location list
|
|
---@diagnostic disable-next-line: param-type-mismatch
|
|
vim.fn.setloclist(0, {}, " ", options)
|
|
|
|
-- open the location list when we have more than 1 definitions found,
|
|
-- otherwise, jump directly to the definition
|
|
if #options.items > 1 then
|
|
vim.cmd.lopen()
|
|
else
|
|
vim.cmd([[silent! lfirst]])
|
|
end
|
|
end,
|
|
}
|
|
end, { desc = "go to definition" })
|
|
map("n", "<C-]>", vim.lsp.buf.definition)
|
|
map("n", "K", function()
|
|
vim.lsp.buf.hover {
|
|
border = "single",
|
|
max_height = 20,
|
|
max_width = 130,
|
|
close_events = { "CursorMoved", "BufLeave", "WinLeave", "LSPDetach" },
|
|
}
|
|
end)
|
|
map("n", "<C-k>", vim.lsp.buf.signature_help)
|
|
map("n", "<space>rn", vim.lsp.buf.rename, { desc = "varialbe rename" })
|
|
map("n", "<space>ca", vim.lsp.buf.code_action, { desc = "LSP code action" })
|
|
map("n", "<space>wa", vim.lsp.buf.add_workspace_folder, { desc = "add workspace folder" })
|
|
map("n", "<space>wr", vim.lsp.buf.remove_workspace_folder, { desc = "remove workspace folder" })
|
|
map("n", "<space>wl", function()
|
|
vim.print(vim.lsp.buf.list_workspace_folders())
|
|
end, { desc = "list workspace folder" })
|
|
|
|
-- Set some key bindings conditional on server capabilities
|
|
-- Disable ruff hover feature in favor of Pyright
|
|
if client.name == "ruff" then
|
|
client.server_capabilities.hoverProvider = false
|
|
end
|
|
end,
|
|
nested = true,
|
|
desc = "Configure buffer keymap and behavior based on LSP",
|
|
})
|
|
|
|
-- Enable lsp servers when they are available
|
|
local capabilities = require("lsp_utils").get_default_capabilities()
|
|
|
|
-- `*` will set default config for all lsp
|
|
vim.lsp.config("*", {
|
|
capabilities = capabilities,
|
|
flags = {
|
|
debounce_text_changes = 500,
|
|
},
|
|
})
|
|
|
|
vim.lsp.config("basedpyright", {
|
|
capabilities = capabilities,
|
|
offset_encoding = "utf-16",
|
|
settings = {
|
|
python = {
|
|
analysis = {
|
|
typeCheckingMode = "strict",
|
|
},
|
|
},
|
|
},
|
|
})
|
|
|
|
vim.lsp.config("ruff", {
|
|
capabilities = capabilities,
|
|
offset_encoding = "utf-8",
|
|
})
|
|
|
|
-- A mapping from lsp server name to the executable name
|
|
local enabled_lsp_servers = {
|
|
basedpyright = "basedpyright-langserver",
|
|
ruff = "ruff",
|
|
lua_ls = "lua-language-server",
|
|
-- clangd = "clangd",
|
|
vimls = "vim-language-server",
|
|
bashls = "bash-language-server",
|
|
yamlls = "yaml-language-server",
|
|
gopls = "gopls",
|
|
-- the server can be install via homebrew: brew install golangci-lint-langserver
|
|
-- golangci-lint also needs to be installed: https://github.com/golangci/golangci-lint
|
|
golangci_lint_ls = "golangci-lint-langserver",
|
|
|
|
-- to install codebook, run `brew install codebook-lsp`
|
|
-- codebook = "codebook-lsp"
|
|
}
|
|
|
|
for server_name, lsp_executable in pairs(enabled_lsp_servers) do
|
|
if utils.executable(lsp_executable) then
|
|
vim.lsp.enable(server_name)
|
|
else
|
|
local msg = string.format(
|
|
"Executable '%s' for server '%s' not found! Server will not be enabled",
|
|
lsp_executable,
|
|
server_name
|
|
)
|
|
vim.notify(msg, vim.log.levels.WARN, { title = "Nvim-config" })
|
|
end
|
|
end
|
|
|
|
-- LSP related command
|
|
|
|
vim.api.nvim_create_user_command("LspInfo", "checkhealth vim.lsp", {
|
|
desc = "Show LSP Info",
|
|
})
|
|
|
|
vim.api.nvim_create_user_command("LspLog", function(_)
|
|
local log_path = vim.lsp.log.get_filename()
|
|
|
|
vim.cmd(string.format("edit %s", log_path))
|
|
end, {
|
|
desc = "Show LSP log",
|
|
})
|
|
|
|
vim.api.nvim_create_user_command("LspRestart", "lsp restart", {
|
|
desc = "Restart LSP",
|
|
})
|
|
|
|
--- show LSP progress (works on Ghostty)
|
|
vim.api.nvim_create_autocmd("LspProgress", {
|
|
callback = function(ev)
|
|
local value = ev.data.params.value
|
|
vim.api.nvim_echo({ { value.message or "done" } }, false, {
|
|
id = "lsp." .. ev.data.client_id,
|
|
kind = "progress",
|
|
source = "vim.lsp",
|
|
title = value.title,
|
|
status = value.kind ~= "end" and "running" or "success",
|
|
percent = value.percentage,
|
|
})
|
|
end,
|
|
})
|
|
|
|
-- this controls the LSP inlayHints behavior
|
|
vim.g.lsp_inlay_hint_enabled = false
|
|
|
|
local update_inlayhint = function(enable)
|
|
-- Some LSP server supports inlay hint, but disable this feature by default, so you may need to
|
|
-- enable inlay hint in the LSP server config.
|
|
vim.lsp.inlay_hint.enable(enable)
|
|
end
|
|
|
|
vim.api.nvim_create_user_command("LspInlayHints", function(context)
|
|
-- vim.print("context", context)
|
|
if context["args"] == "enable" then
|
|
vim.g.lsp_inlay_hint_enabled = true
|
|
end
|
|
|
|
if context["args"] == "disable" then
|
|
vim.g.lsp_inlay_hint_enabled = false
|
|
end
|
|
|
|
update_inlayhint(vim.g.lsp_inlay_hint_enabled)
|
|
end, {
|
|
bang = false,
|
|
nargs = 1,
|
|
force = true,
|
|
desc = "Toggle LSP inlayHints",
|
|
complete = function()
|
|
return { "enable", "disable" }
|
|
end,
|
|
})
|