Files
nvim/lua/conf/plugins/mason-lspconfig.lua

370 lines
13 KiB
Lua

local misc = require('core.misc')
local map, auto, augroup = misc.map, misc.auto, misc.augroup
return { 'williamboman/mason-lspconfig.nvim',
requires = {
'williamboman/mason.nvim',
'mfussenegger/nvim-jdtls',
'neovim/nvim-lspconfig'
},
function()
local util = require('lspconfig.util')
-- configure lsp when attached
local function lsp_attach(client, bufnr)
-- helper function(s)
local function set_lsp_sign(name, text)
vim.fn.sign_define(name, { text = text, texthl = name })
end
set_lsp_sign("DiagnosticSignError", "x")
set_lsp_sign("DiagnosticSignWarn" , "!")
set_lsp_sign("DiagnosticSignInfo" , "i")
set_lsp_sign("DiagnosticSignHint" , "h")
local opts = { buffer = bufnr }
-- LSP actions
map('n', 'K', vim.lsp.buf.hover, opts)
map('n', 'gD', vim.lsp.buf.definition, opts)
-- map('n', 'gD', '<cmd>lua vim.lsp.buf.declaration()<cr>')
map('n', 'gI', vim.lsp.buf.implementation, opts)
map('n', 'gY', vim.lsp.buf.type_definition, opts)
map('n', 'gR', vim.lsp.buf.references, opts)
map('n', '<S-Tab>', vim.lsp.buf.signature_help, opts)
map('n', '<leader>lr', vim.lsp.buf.rename, opts)
map('n', '<F2>', vim.lsp.buf.rename, opts)
map('n', 'gA', vim.lsp.buf.code_action, {
buffer = bufnr,
desc = 'check code actions',
})
map('n', '<F4>', vim.lsp.buf.code_action, {
buffer = bufnr,
desc = 'check code actions'
})
-- Diagnostics
map('n', '[d', vim.diagnostic.goto_prev)
map('n', ']d', vim.diagnostic.goto_next)
end
-- setup lsp capabilities
local capabilities = vim.lsp.protocol.make_client_capabilities()
capabilities.textDocument.completion.completionItem = {
documentationFormat = { "markdown", "plaintext" },
snippetSupport = true,
preselectSupport = true,
insertReplaceSupport = true,
labelDetailsSupport = true,
deprecatedSupport = true,
commitCharactersSupport = true,
tagSupport = {
valueSet = { 1 }
},
resolveSupport = {
properties = {
"documentation",
"detail",
"additionalTextEdits"
}
}
}
-- setup language servers
require('mason-lspconfig').setup {
ensure_installed = {
"lua_ls",
"clangd",
"jdtls",
"tsserver",
"phpactor",
"html",
"cssls",
"bashls",
"zls"
-- "asm-lsp", -- seems to be broken
}
}
require('mason-lspconfig').setup_handlers {
function(server_name)
require('lspconfig')[server_name].setup {
on_attach = lsp_attach,
capabilities = capabilities
}
end,
-- setup luals
["lua_ls"] = function(server_name)
local root_files = { '.luarc.json', '.luarc.jsonc', '.luacheckrc',
'.stylua.toml', 'stylua.toml', 'selene.toml', 'selene.yml',
'README.md'
}
-- FIXME: for some reason luals randomly resets the indentation of code
-- when pressing o or O. Right now this is a minor annoyance I will deal
-- with in exchange for really good lua lsp support.
--
-- FIXME: luals also seems to start up twice and sends back twice the
-- completions (one configured with the below settings and one without)
require('lspconfig')[server_name].setup {
on_attach = lsp_attach,
settings = {
Lua = {
diagnostics = {
globals = { "vim", 'mp' }
},
runtime = {
version = 'LuaJIT'
},
format = {
enable = false
},
workspace = {
checkThirdParty = false,
library = {
vim.env.VIMRUNTIME
}
}
}
},
root_dir = function(fname)
local root = util.root_pattern(unpack(root_files))(fname)
if root and root ~= vim.env.HOME then
return root
end
root = util.root_pattern('lua/')(fname)
if root then
return root
end
return util.find_git_ancestor(fname)
end
}
end,
-- setup clangd
["clangd"] = function(server_name)
require('lspconfig')[server_name].setup {
on_attach = function(client, bufnr)
lsp_attach(client, bufnr)
-- add some clangd specific mappings
local opts = { buffer = bufnr }
map("n", "<leader>o", "<cmd>ClangdSwitchSourceHeader<CR>", opts)
end,
capabilities = capabilities,
cmd = {
"clangd",
"--background-index",
"--clang-tidy",
"--header-insertion=iwyu",
"--completion-style=detailed",
"--function-arg-placeholders",
"--fallback-style=llvm"
},
init_options = {
usePlaceholders = true,
clangdFileStatus = true,
fallback_flags = {
"-xc" -- makes clangd think we're using c instead of c++
}
}
}
end,
-- setup jdtls
["jdtls"] = function(server_name)
auto("Filetype", {
pattern = "java",
callback = function()
-- must be a java interpreter of version 17 or greater
local java = "java"
local buffer = {}
---@type function
local startlsp
-- check if version of java in use is high enough
vim.fn.jobstart({ java, vim.fn.stdpath('config').."/extras/JavaVersion.java" }, {
stdin = nil,
on_stdout = function(_, data, _)
table.insert(buffer, table.concat(data))
end,
on_exit = function(_, exit_code, _)
local v = vim.version.parse(table.concat(buffer))
-- if there's an error, no version info, or the java version is
-- less than 17 stop the lsp from starting
if exit_code ~= 0 then
vim.notify(string.format(
"java version check failed: exit code %s", exit_code),
vim.log.levels.ERROR, { title = misc.appid })
return
elseif not v then
vim.notify("no java version info found", vim.log.levels.ERROR,
{ title = misc.appid })
return
elseif v.major < 17 then
vim.notify(string.format(
"java version %s < 17.0.0 Cannot run jdtls, bailing out",
v[1].."."..v[2].."."..v[3]),
vim.log.levels.ERROR, { title = misc.appid })
return
end
startlsp()
end
})
function startlsp()
local ok, jdtls = pcall(require, "jdtls")
if not ok then
vim.notify("jdtls not found, can't start java lsp",
vim.log.levels.ERROR, {})
return
end
local config = {}
config.on_attach = function(client, bufnr)
lsp_attach(client, bufnr)
-- add some jdtls specific mappings
local opts = { buffer = bufnr }
map('n', 'cri', jdtls.organize_imports, opts)
map('n', 'crv', jdtls.extract_variable, opts)
map('n', 'crc', jdtls.extract_constant, opts)
map('x', 'crv', "<esc><cmd>lua require('jdtls').extract_variable(true)<cr>", opts)
map('x', 'crc', "<esc><cmd>lua require('jdtls').extract_constant(true)<cr>", opts)
map('x', 'crm', "<esc><Cmd>lua require('jdtls').extract_method(true)<cr>", opts)
-- refresh the codelens every time after writing the file
local jdtls_cmds = augroup("jdtls_cmds")
pcall(vim.lsp.codelens.refresh)
auto('BufWritePost', {
buffer = bufnr,
group = jdtls_cmds,
desc = 'refresh codelens',
callback = function()
pcall(vim.lsp.codelens.refresh)
end
})
end
-- setup path stuff
local path = {}
local jdtls_install = require('mason-registry').get_package('jdtls'):get_install_path()
path.data_dir = vim.fn.stdpath('cache')..'/nvim-jdtls'
path.java_agent = jdtls_install..'/lombok.jar'
path.launcher_jar = vim.fn.glob(jdtls_install..'/plugins/org.eclipse.equinox.launcher_*.jar')
path.platform_config = jdtls_install..'/config_linux'
path.bundles = {}
-- data dir
local data_dir = path.data_dir..'/'..vim.fn.fnamemodify(vim.fn.getcwd(), ':p:h:t')
-- enable basic capabilities
config.capabilities = capabilities
-- enable some extended client capabilities
local extendedClientCapabilities = jdtls.extendedClientCapabilities
extendedClientCapabilities.resolveAdditionalTextEditsSupport = true
-- command to start the lsp server
config.cmd = {
java, -- this has to be java17 or newer
'-Declipse.application=org.eclipse.jdt.ls.core.id1',
'-Dosgi.bundles.defaultStartLevel=4',
'-Declipse.product=org.eclipse.jdt.ls.core.product',
'-Dlog.protocol=true',
'-Dlog.level=ALL',
'-Xmx1G',
'--add-modules=ALL-SYSTEM',
'--add-opens', 'java.base/java.util=ALL-UNNAMED',
'--add-opens', 'java.base/java.lang=ALL-UNNAMED',
'-jar', path.launcher_jar,
'-configuration', path.platform_config,
'-data', data_dir
}
-- settings
config.settings = {
java = {
eclipse = { downloadSources = true },
gradle = { enabled = true },
maven = { downloadSources = true },
implementationsCodeLens = { enabled = true },
referencesCodeLens = { enabled = true },
references = { includeDecompiledSources = true },
symbols = { includeSourceMethodDeclarations = true },
inlayHints = {
parameterNames = {
enabled = "all"
}
},
completion = {
favoriteStaticMembers = {
"org.hamcrest.MatcherAssert.assertThat",
"org.hamcrest.Matchers.*",
"org.hamcrest.CoreMatchers.*",
"org.junit.jupiter.api.Assertions.*",
"java.util.Objects.requireNonNull",
"java.util.Objects.requireNonNullElse",
"org.mockito.Mockito.*"
},
filteredTypes = {
"com.sun.*",
"io.micrometer.shaded.*",
"java.awt.*",
"jdk.*",
"sun.*"
},
importOrder = {
"java",
"javax",
"com",
"org"
}
},
sources = {
organizeImports = {
starThreshold = 9999,
staticStarThreshold = 9999
}
},
codeGeneration = {
toString = {
template = '${object.className}{${member.name()}=${member.value}, ${otherMembers}}'
},
hashCodeEquals = { useJava7Objects = true },
useBlocks = true,
}
}
}
config.signatureHelp = { enabled = true }
config.flags = { allow_incremental_sync = true }
-- disable all messages from printing
config.handlers = {
['language/status'] = function() end
}
config.init_options = {
extendedClientCapabilities = extendedClientCapabilities,
}
config.root_dir = vim.fs.root(0, { ".git", "mvnw", ".gradle",
"gradlew" })
-- start it up
jdtls.start_or_attach(config)
end
end
})
end
}
end
}