diff options
Diffstat (limited to 'lua/conf/plugins/mason-lspconfig.lua')
-rw-r--r-- | lua/conf/plugins/mason-lspconfig.lua | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/lua/conf/plugins/mason-lspconfig.lua b/lua/conf/plugins/mason-lspconfig.lua new file mode 100644 index 0000000..edeaf93 --- /dev/null +++ b/lua/conf/plugins/mason-lspconfig.lua @@ -0,0 +1,369 @@ +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 +} |