dotfiles/nvim/lua/plugins/lsp.lua

295 lines
8.9 KiB
Lua

-- LSP support
--
-- https://github.com/neovim/nvim-lspconfig
-- https://github.com/hrsh7th/cmp-nvim-lsp
-- https://github.com/SmiteshP/nvim-navic (used in the statusline)
local M = {
"neovim/nvim-lspconfig",
dependencies = {
"hrsh7th/cmp-nvim-lsp",
"SmiteshP/nvim-navic",
},
}
M.formatting = {}
M.formatting.autoformat = true
function M.formatting.toggle()
M.formatting.autoformat = not M.formatting.autoformat
local msg = M.formatting.autoformat and "Enabled" or "Disabled"
local notify = require("plugins.notify")
notify.info(msg .. " format on save", { title = "Formatting" })
end
local CONFORM_FT = { javascript = true, typescript = true }
function M.formatting.format()
if M.formatting.autoformat then
if CONFORM_FT[vim.bo.filetype] then
require("conform").format()
return
elseif vim.lsp.buf.format then
vim.lsp.buf.format()
else
vim.lsp.buf.formatting_sync()
end
end
end
function M.formatting.setup(client, bufnr)
local ft = vim.api.nvim_buf_get_option(bufnr, "filetype")
local enable = true
if CONFORM_FT[ft] then
enable = false
end
client.server_capabilities.documentFormattingProvider = enable
vim.cmd([[
augroup LspFormat
autocmd! * <buffer>
autocmd BufWritePre <buffer> lua require("plugins.lsp").formatting.format()
augroup END
]])
end
function M.show_documentation()
local filetype = vim.bo.filetype
if vim.tbl_contains({ "vim", "help" }, filetype) then
vim.cmd("h " .. vim.fn.expand("<cword>"))
elseif vim.tbl_contains({ "man" }, filetype) then
vim.cmd("Man " .. vim.fn.expand("<cword>"))
elseif vim.fn.expand("%:t") == "Cargo.toml" and require("crates").popup_available() then
require("crates").show_popup()
else
vim.lsp.buf.hover()
end
end
-- Use an on_attach function to only map keys after the language server attaches to the current buffer
function M.on_attach(client, bufnr)
local function buf_set_keymap(...) vim.api.nvim_buf_set_keymap(bufnr, ...) end
local function buf_set_option(...) vim.api.nvim_buf_set_option(bufnr, ...) end
-- Enable completion triggered by <c-x><c-o>
buf_set_option('omnifunc', 'v:lua.vim.lsp.omnifunc')
-- Attach nvim-navic to the LSP server if 'documentSymbolProvider' is present
if client.server_capabilities.documentSymbolProvider then
local ok, navic = pcall(require, "nvim-navic")
if ok then
navic.attach(client, bufnr)
else
vim.notify("Failed to load nvim-navic", vim.log.levels.WARN)
end
end
-- Set formatting on save
-- vim.api.nvim_command [[autocmd BufWritePre <buffer> lua vim.lsp.buf.formatting_sync()]]
M.formatting.setup(client, bufnr)
-- Attach LSP signatures
require("lsp_signature").on_attach()
-- Enable inlay hints
-- vim.lsp.inlay_hint.enable(bufnr, true)
vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
-- Show diagnostics in floating window on cursor
vim.api.nvim_create_autocmd("CursorHold", {
buffer = bufnr,
callback = function()
local opts = {
focusable = false,
close_events = { "BufLeave", "CursorMoved", "InsertEnter", "FocusLost" },
border = "rounded",
source = "always",
prefix = " ",
scope = "cursor"
}
vim.diagnostic.open_float(nil, opts)
end
})
-- Mappings
-- See `:help vim.lsp.*` for documentation on any of the below functions
local opts = { noremap = true, silent = true }
buf_set_keymap('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<CR>', opts)
-- NOTE: I use Telescope for definitions now, as it's easier to browse
-- buf_set_keymap('n', 'gd', '<cmd>lua vim.lsp.buf.definition()<CR>', opts)
buf_set_keymap('n', 'K', '<cmd>lua vim.lsp.buf.hover()<CR>', opts)
-- buf_set_keymap('n', 'K', M.show_documentation, opts)
buf_set_keymap('n', 'gi', '<cmd>lua vim.lsp.buf.implementation()<CR>', opts)
buf_set_keymap('n', '<C-k>', '<cmd>lua vim.lsp.buf.signature_help()<CR>', opts)
buf_set_keymap('n', '<space>cwa',
'<cmd>lua vim.lsp.buf.add_workspace_folder()<CR>', {
desc = "Add folder to workspace",
noremap = true,
silent = true
})
buf_set_keymap('n', '<space>cwr',
'<cmd>lua vim.lsp.buf.remove_workspace_folder()<CR>', {
desc = "Remove folder from workspace",
noremap = true,
silent = true
})
buf_set_keymap('n', '<space>cwl',
'<cmd>lua print(vim.inspect(vim.lsp.buf.list_workspace_folders()))<CR>',
{ desc = "List workspace", noremap = true, silent = true })
-- buf_set_keymap('n', '<space>D', '<cmd>lua vim.lsp.buf.type_definition()<CR>',
-- { desc = "Show Type Definition", noremap = true, silent = true })
buf_set_keymap('n', '<space>cr', '<cmd>lua vim.lsp.buf.rename()<CR>',
{ desc = "Rename symbol", noremap = true, silent = true })
buf_set_keymap('n', '<space>ca', '<cmd>lua vim.lsp.buf.code_action()<CR>',
{ desc = "Code actions", noremap = true, silent = true })
-- NOTE: I use Telescope for references now, as it's easier to browse
-- buf_set_keymap('n', 'gr', '<cmd>lua vim.lsp.buf.references()<CR>', opts)
-- buf_set_keymap('n', '<space>e',
-- '<cmd>lua vim.lsp.diagnostic.show_line_diagnostics()<CR>', {
-- desc = "Show line diagnostics",
-- noremap = true,
-- silent = true
-- })
-- See `plugins/mini` as `mini-bracketed` is doing this now
-- buf_set_keymap('n', '[d', '<cmd>lua vim.diagnostic.goto_prev()<CR>', opts)
-- buf_set_keymap('n', ']d', '<cmd>lua vim.diagnostic.goto_next()<CR>', opts)
buf_set_keymap('n', '<space>q', '<cmd>lua vim.diagnostic.set_loclist()<CR>', {
desc = "Diagnostics to loclist",
noremap = true,
silent = true
})
-- buf_set_keymap('n', 'gf', '<cmd>lua vim.lsp.buf.formatting()<CR>', opts)
end
function M.get_capabilities()
if M.capabilities then
return M.capabilities
end
local cmp_nvim_lsp = require("cmp_nvim_lsp")
if type(cmp_nvim_lsp.default_capabilities) == "function" then
M.capabilities = cmp_nvim_lsp.default_capabilities()
else
M.capabilities = cmp_nvim_lsp.update_capabilities(vim.lsp.protocol
.make_client_capabilities())
end
return M.capabilities
end
function M.config()
local nvim_lsp = require("lspconfig")
vim.diagnostic.config({
signs = true,
float = { source = "always", border = "rounded", prefix = " " },
virtual_text = {
source = "always",
format = function(diagnostic)
if #diagnostic.message > 60 then
return string.sub(diagnostic.message, 1, 60) .. "..."
else
return diagnostic.message
end
end
}
})
-- Change the border of documentation hover windows
vim.lsp.handlers["textDocument/hover"] =
vim.lsp.with(vim.lsp.handlers.hover, { border = "rounded" })
vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with(
vim.lsp.handlers
.signature_help,
{ border = "rounded" })
-- Get our initial set of capabilities
local capabilities = M.get_capabilities()
-- Setup the Python and TypeScript servers
local servers = { 'pyright', 'ts_ls', 'tailwindcss' }
for _, lsp in ipairs(servers) do
nvim_lsp[lsp].setup {
on_attach = M.on_attach,
flags = { debounce_text_changes = 150 },
capabilities = capabilities
}
end
-- Setup the clangd server
local clangd_path = nil
if vim.fn.filereadable("/usr/bin/clangd") == 1 then
clangd_path = "/usr/bin/clangd"
elseif vim.loop.os_uname().sysname == "Darwin" and
vim.fn.filereadable("/opt/homebrew/opt/llvm/bin/clangd") == 1 then
clangd_path = "/opt/homebrew/opt/llvm/bin/clangd"
elseif vim.fn.filereadable("/home/blake/.local/share/nvim/mason/bin/clangd") then
clangd_path = "/home/blake/.local/share/nvim/mason/bin/clangd"
else
print("Unable to locate 'clangd'")
end
nvim_lsp.clangd.setup {
cmd = { clangd_path },
filetypes = { "c", "cpp", "objc", "objcpp" },
on_attach = M.on_attach,
flags = { debounce_text_changes = 150 },
capabilities = vim.tbl_extend("force", {}, capabilities, {
-- https://github.com/jose-elias-alvarez/null-ls.nvim/issues/428
offsetEncoding = { "utf-16" }
})
}
-- Setup the Lua server
nvim_lsp.lua_ls.setup {
on_attach = M.on_attach,
capabilities = capabilities,
settings = {
Lua = {
runtime = { version = 'LuaJIT' },
diagnostics = {
-- Get the langauge server to recognize the `vim` global
globals = { 'vim' }
},
workspace = {
-- Make the server aware of Neovim runtime files
library = vim.api.nvim_get_runtime_file("", true)
},
-- Do not send telemetry data containing a randomized but unique identifier
telemetry = { enable = false }
}
}
}
-- Setup Solidity
nvim_lsp.solidity_ls
.setup { on_attach = M.on_attach, capabilities = capabilities }
-- Setup the Java server
nvim_lsp.jdtls.setup {
cmd = { "jdtls" },
on_attach = M.on_attach,
capabilities = capabilities,
}
-- NOTE: Rust is now activated in 'rustaceanvim.lua'
end
return M