local misc = require("core.misc") local map, auto = misc.map, misc.auto local jdtls = require("jdtls") local jdtls_install = vim.fs.joinpath(vim.fn.stdpath('data'), "/mason/packages/jdtls") local java_dap_install = vim.fs.joinpath(vim.fn.stdpath('data'), "/mason/packages/java-debug-adapter") -- make sure to check if things with 💀 need updating local config = { cmd = { "/usr/lib/jvm/openjdk21/bin/java", -- 💀 "-jar", vim.fn.glob(jdtls_install.."/plugins/org.eclipse.equinox.launcher_*.jar"), -- 💀 "-configuration", jdtls_install.."/config_linux", "-data", vim.fn.stdpath("cache").."/nvim-jdtls", "--add-modules=ALL-SYSTEM", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.util=ALL-UNNAMED", "-Declipse.application=org.eclipse.jdt.ls.core.id1", "-Declipse.product=org.eclipse.jdt.ls.core.product", "-Dlog.level=ALL", "-Dlog.protocol=true", "-Dosgi.bundles.defaultStartLevel=4", "-Xmx1G", }, root_dir = vim.fs.dirname(vim.fs.find({ "gradlew", ".git", "mvnw", "settings.gradle", -- Gradle (multi-project) "settings.gradle.kts", -- Gradle (multi-project) "build.xml", -- Ant "pom.xml" -- Maven }, { upward = true })[1]), on_attach = function(_, bufnr) jdtls.setup.add_commands() -- 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", function() jdtls.extract_variable(true) end, opts) map("x", "crc", function() jdtls.extract_constant(true) end, opts) map("x", "crm", function() jdtls.extract_method(true) end, opts) pcall(vim.lsp.codelens.refresh) auto("BufWritePost", { buffer = bufnr, desc = "refresh codelens", callback = function() pcall(vim.lsp.codelens.refresh) end }) -- setup nvim-dap require("dap").adapters.java = nil -- remove any old java adapters jdtls.setup_dap({ hotcodereplace = "auto" }) require("jdtls.dap").setup_dap_main_class_configs() end, -- don"t print out status messages handlers = { ["language/status"] = function() end }, init_options = { bundles = { vim.fs.joinpath(java_dap_install, vim.fn.glob("/extension/server/com.microsoft.java.debug.plugin-*.jar", true) ) } } } -- generate the path to the java file(s) ---@type string|nil local cache_path = vim.fs.joinpath(vim.fn.stdpath("cache"), "/JavaVersion.class") ---@type string|nil local src_path = vim.fs.joinpath(vim.fn.stdpath("config"), "/extras/JavaVersion.java") -- if either path is invalid if not cache_path or not src_path then return end --- build a cache of the JavaVersion code local function build_cache() -- check if we have javac vim.system({ "javac" }, {}, function(out) if out.code == 127 then cache_path = nil return end -- compile our code vim.system({ "javac", src_path, "-d", vim.fn.stdpath("cache") }, {}, function(out) if out.code ~= 0 then cache_path = nil end end) end) end -- check if we have a compiled version of JavaVersion local f, _ = io.open(cache_path, "r") if not f then -- if we don"t have a cache build_cache() else io.close(f) end local function version_check() -- check the java version local out = vim.system({ config.cmd[1], -- use the same java executable that the lsp will be using (cache_path and "JavaVersion") or src_path }, { cwd = vim.fn.stdpath("cache"), text = true }):wait() -- parse the version information aquired local v = vim.version.parse(out.stdout) -- if there's an error, no version info, or the java version is -- less than 21 stop the lsp from starting if out.code ~= 0 then vim.notify(string.format( "java version check failed: exit code %s", out.code), vim.log.levels.ERROR, { title = misc.appid }) vim.notify(string.format( "%s", vim.inspect(out.stdout)), vim.log.levels.ERROR, { title = misc.appid }) return false elseif not v then vim.notify("no java version info found", vim.log.levels.ERROR, { title = misc.appid }) return false elseif v.major < 21 then vim.notify(string.format( "java version %s < 21.0.0 Cannot run jdtls, bailing out", v[1] .. "." .. v[2] .. "." .. v[3]), vim.log.levels.ERROR, { title = misc.appid }) return false end return true end -- start the jdtls with dap! if not version_check() then return end jdtls.start_or_attach(config)