diff --git a/.devcontainer/config/nvim/init.lua b/.devcontainer/config/nvim/init.lua index 2b7a52d..b13bd64 100644 --- a/.devcontainer/config/nvim/init.lua +++ b/.devcontainer/config/nvim/init.lua @@ -21,7 +21,15 @@ require('lazy').setup({ 'nvim-java/nvim-java', dir = '/workspaces/nvim-java', config = function() - require('java').setup() + require('java').setup({ + jdk = { + auto_install = false, + }, + log = { + use_console = false, + level = 'debug', + }, + }) vim.lsp.config('jdtls', { handlers = { ['language/status'] = function(_, data) @@ -36,6 +44,18 @@ require('lazy').setup({ vim.lsp.enable('jdtls') end, }, + { + 'ibhagwan/fzf-lua', + -- optional for icon support + dependencies = { 'nvim-tree/nvim-web-devicons' }, + -- or if using mini.icons/mini.nvim + -- dependencies = { "nvim-mini/mini.icons" }, + ---@module "fzf-lua" + ---@type fzf-lua.Config|{} + ---@diagnostics disable: missing-fields + opts = {}, + ---@diagnostics enable: missing-fields + }, }) -- Basic settings @@ -46,85 +66,105 @@ vim.opt.tabstop = 2 vim.opt.shiftwidth = 2 vim.opt.expandtab = false vim.opt.completeopt = { 'menu', 'menuone', 'noselect' } +vim.opt.number = true +vim.opt.relativenumber = true + +local k = vim.keymap.set -vim.keymap.set('n', '', 'q') +k('n', '', 'q') if colemak then - vim.keymap.set('n', '', '') - vim.keymap.set('n', 'E', 'K') - vim.keymap.set('n', 'H', 'I') - vim.keymap.set('n', 'K', 'N') - vim.keymap.set('n', 'L', 'E') - vim.keymap.set('n', 'N', 'J') - vim.keymap.set('n', 'e', '') - vim.keymap.set('n', 'h', 'i') - vim.keymap.set('n', 'i', '') - vim.keymap.set('n', 'j', 'm') - vim.keymap.set('n', 'k', 'n') - vim.keymap.set('n', 'l', 'e') - vim.keymap.set('n', 'm', '') - vim.keymap.set('n', 'n', '') + k('n', '', '') + k('n', 'E', 'K') + k('n', 'H', 'I') + k('n', 'K', 'N') + k('n', 'L', 'E') + k('n', 'N', 'J') + k('n', 'e', '') + k('n', 'h', 'i') + k('n', 'i', '') + k('n', 'j', 'm') + k('n', 'k', 'n') + k('n', 'l', 'e') + k('n', 'm', '') + k('n', 'n', '') end vim.api.nvim_create_autocmd('LspAttach', { callback = function(args) vim.lsp.completion.enable(true, args.data.client_id, args.buf, { autotrigger = true }) - vim.keymap.set('i', '', function() + k('i', '', function() vim.lsp.completion.get() end, { buffer = args.buf }) if colemak then - vim.keymap.set('i', '', '', { buffer = args.buf }) - vim.keymap.set('i', '', '', { buffer = args.buf }) + k('i', '', '', { buffer = args.buf }) + k('i', '', '', { buffer = args.buf }) end end, }) -vim.keymap.set('n', ']d', function() +k('n', ']d', function() vim.diagnostic.jump({ count = 1, float = true }) end, { desc = 'Jump to next diagnostic' }) -vim.keymap.set('n', '[d', function() +k('n', '[d', function() vim.diagnostic.jump({ count = -1, float = true }) end, { desc = 'Jump to previous diagnostic' }) -vim.keymap.set('n', 'ta', vim.lsp.buf.code_action, {}) +k('n', 'ta', vim.lsp.buf.code_action, {}) -- DAP keymaps -vim.keymap.set('n', 'dd', function() +k('n', 'dd', function() require('dap').toggle_breakpoint() end, { desc = 'Toggle breakpoint' }) -vim.keymap.set('n', 'dc', function() +k('n', 'dc', function() require('dap').continue() end, { desc = 'Continue' }) -vim.keymap.set('n', 'dn', function() +k('n', 'dn', function() require('dap').step_over() end, { desc = 'Step over' }) -vim.keymap.set('n', 'di', function() +k('n', 'di', function() require('dap').step_into() end, { desc = 'Step into' }) -vim.keymap.set('n', 'do', function() +k('n', 'do', function() require('dap').step_out() end, { desc = 'Step out' }) -vim.keymap.set('n', 'dr', function() +k('n', 'dr', function() require('dap').repl.open() end, { desc = 'Open REPL' }) -vim.keymap.set('n', 'dl', function() +k('n', 'dl', function() require('dap').run_last() end, { desc = 'Run last' }) -vim.keymap.set('n', 'dt', function() +k('n', 'dt', function() require('dap').terminate() end, { desc = 'Terminate' }) -vim.keymap.set('n', 'gd', function() +k('n', 'gd', function() vim.lsp.buf.definition() end, { desc = 'Terminate' }) -vim.keymap.set('n', 'm', "vnewput = execute('messages')") +k('n', 'tt', function() + require('fzf-lua').lsp_document_symbols() +end) + +k('n', 'm', "vnewput = execute('messages')") + +k('n', 'nn', 'JavaRunnerRunMain', { desc = 'Run main' }) +k('n', 'ne', 'JavaRunnerStopMain', { desc = 'Stop main' }) +k('n', 'nt', 'JavaTestDebugCurrentClass', { desc = 'Debug test' }) +k('n', 'ns', 'JavaTestRunCurrentClass', { desc = 'Run test' }) + +k('t', 'yy', '', { desc = 'Exit terminal mode' }) + +k('n', '', 'j', { desc = 'Window down' }) +k('n', '', 'k', { desc = 'Window up' }) +k('n', '', 'h', { desc = 'Window left' }) +k('n', '', 'l', { desc = 'Window right' }) diff --git a/.devcontainer/config/nvim/lazy-lock.json b/.devcontainer/config/nvim/lazy-lock.json index 3737ab9..933e059 100644 --- a/.devcontainer/config/nvim/lazy-lock.json +++ b/.devcontainer/config/nvim/lazy-lock.json @@ -1,6 +1,8 @@ { + "fzf-lua": { "branch": "main", "commit": "de0fd4a21ee29cf6532d0c3bcae08a0b25d99b6a" }, "lazy.nvim": { "branch": "main", "commit": "85c7ff3711b730b4030d03144f6db6375044ae82" }, "nui.nvim": { "branch": "main", "commit": "de740991c12411b663994b2860f1a4fd0937c130" }, "nvim-dap": { "branch": "master", "commit": "5860c7c501eb428d3137ee22c522828d20cca0b3" }, + "nvim-web-devicons": { "branch": "master", "commit": "8dcb311b0c92d460fac00eac706abd43d94d68af" }, "spring-boot.nvim": { "branch": "main", "commit": "218c0c26c14d99feca778e4d13f5ec3e8b1b60f0" } } diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 8fe9ee8..3fc365c 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -6,11 +6,13 @@ "ghcr.io/devcontainers/features/git:1": {}, "ghcr.io/devcontainers/features/java:1": {}, "ghcr.io/devcontainers/features/python:1": {}, + "ghcr.io/devcontainers/features/node:1": {}, "ghcr.io/devcontainers-extra/features/wget-apt-get:1": {}, "ghcr.io/duduribeiro/devcontainer-features/neovim:1": { "version": "nightly" }, - "ghcr.io/devcontainers-extra/features/springboot-sdkman:2": {} + "ghcr.io/devcontainers-extra/features/springboot-sdkman:2": {}, + "ghcr.io/devcontainers-extra/features/fzf:1": {} }, "postCreateCommand": "bash .devcontainer/setup.sh", "customizations": { diff --git a/CHANGELOG.md b/CHANGELOG.md index 7e2a7fd..fd72263 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## [4.0.2](https://github.com/nvim-java/nvim-java/compare/v4.0.1...v4.0.2) (2025-12-10) + + +### Bug Fixes + +* vim.lsp.buf.document_symbol returns nothing for jdtls ([#449](https://github.com/nvim-java/nvim-java/issues/449)) ([625f48f](https://github.com/nvim-java/nvim-java/commit/625f48ffedc735ac6284316e16daa99ba012a996)) + ## [4.0.1](https://github.com/nvim-java/nvim-java/compare/v4.0.0...v4.0.1) (2025-12-05) diff --git a/lua/java-core/constants/java_version.lua b/lua/java-core/constants/java_version.lua index d8c8459..2fc2de4 100644 --- a/lua/java-core/constants/java_version.lua +++ b/lua/java-core/constants/java_version.lua @@ -1,14 +1,4 @@ return { ['1.43.0'] = { from = 17, to = 17 }, - ['1.44.0'] = { from = 17, to = 21 }, - ['1.45.0'] = { from = 21, to = 21 }, - ['1.46.0'] = { from = 21, to = 21 }, - ['1.46.1'] = { from = 21, to = 21 }, - ['1.47.0'] = { from = 21, to = 21 }, - ['1.48.0'] = { from = 21, to = 21 }, - ['1.49.0'] = { from = 21, to = 21 }, - ['1.50.0'] = { from = 21, to = 21 }, - ['1.51.0'] = { from = 21, to = 21 }, - ['1.52.0'] = { from = 21, to = 21 }, - ['1.53.0'] = { from = 21, to = 21 }, + ['1.54.0'] = { from = 21, to = 25 }, } diff --git a/lua/java-core/ls/servers/jdtls/cmd.lua b/lua/java-core/ls/servers/jdtls/cmd.lua index 3e7c150..bc63ec2 100644 --- a/lua/java-core/ls/servers/jdtls/cmd.lua +++ b/lua/java-core/ls/servers/jdtls/cmd.lua @@ -6,6 +6,7 @@ local log = require('java-core.utils.log2') local err = require('java-core.utils.errors') local java_version_map = require('java-core.constants.java_version') local lsp_utils = require('java-core.utils.lsp') +local str = require('java-core.utils.str') local M = {} @@ -128,7 +129,20 @@ function M.validate_java_version(config, env) local curr_ver = M.get_java_major_version(env) local exp_ver = java_version_map[config.jdtls.version] - if not (curr_ver >= exp_ver.to and curr_ver <= exp_ver.from) then + if not exp_ver then + err.throw( + str.multiline( + 'We maintain a jdlts to java version map to provide a better error message.', + 'The jdtls version you are using is not supported yet', + 'Please open an issue on https://github.com/nvim-java/nvim-java/issues', + 'OR submit a PR', + 'Version map:', + 'https://github.com/nvim-java/nvim-java/blob/main/lua/java-core/constants/java_version.lua' + ) + ) + end + + if not (curr_ver >= exp_ver.from and curr_ver <= exp_ver.to) then local msg = string.format( 'Java version mismatch: JDTLS %s requires Java %d <= java >= %d, but found Java %d', config.jdtls.version, diff --git a/lua/java-core/ls/servers/jdtls/conf.lua b/lua/java-core/ls/servers/jdtls/conf.lua index bf5cf2c..0cd37c1 100644 --- a/lua/java-core/ls/servers/jdtls/conf.lua +++ b/lua/java-core/ls/servers/jdtls/conf.lua @@ -8,7 +8,7 @@ return { advancedOrganizeImportsSupport = true, advancedUpgradeGradleSupport = true, classFileContentsSupport = true, - clientDocumentSymbolProvider = true, + clientDocumentSymbolProvider = false, clientHoverProvider = false, executeClientCommandSupport = true, extractInterfaceSupport = true, diff --git a/lua/java-core/ls/servers/jdtls/init.lua b/lua/java-core/ls/servers/jdtls/init.lua index 654c6b8..dfa263d 100644 --- a/lua/java-core/ls/servers/jdtls/init.lua +++ b/lua/java-core/ls/servers/jdtls/init.lua @@ -21,6 +21,8 @@ function M.get_config(opts) base_conf.root_markers = root.get_root_markers() base_conf.filetypes = filetype.get_filetypes() + log.debug('jdtls config', base_conf) + return base_conf end diff --git a/lua/java-core/ls/servers/jdtls/plugins.lua b/lua/java-core/ls/servers/jdtls/plugins.lua index 16ddb2f..a66ce5b 100644 --- a/lua/java-core/ls/servers/jdtls/plugins.lua +++ b/lua/java-core/ls/servers/jdtls/plugins.lua @@ -1,36 +1,5 @@ -local file = require('java-core.utils.file') -local List = require('java-core.utils.list') -local Manager = require('pkgm.manager') -local log = require('java-core.utils.log2') - local M = {} -local plug_jar_map = { - ['java-test'] = { - 'extension/server/junit-jupiter-api_*.jar', - 'extension/server/junit-jupiter-engine_*.jar', - 'extension/server/junit-jupiter-migrationsupport_*.jar', - 'extension/server/junit-jupiter-params_*.jar', - 'extension/server/junit-platform-commons_*.jar', - 'extension/server/junit-platform-engine_*.jar', - 'extension/server/junit-platform-launcher_*.jar', - 'extension/server/junit-platform-runner_*.jar', - 'extension/server/junit-platform-suite-api_*.jar', - 'extension/server/junit-platform-suite-commons_*.jar', - 'extension/server/junit-platform-suite-engine_*.jar', - 'extension/server/junit-vintage-engine_*.jar', - 'extension/server/org.apiguardian.api_*.jar', - 'extension/server/org.eclipse.jdt.junit4.runtime_*.jar', - 'extension/server/org.eclipse.jdt.junit5.runtime_*.jar', - 'extension/server/org.opentest4j_*.jar', - 'extension/server/com.microsoft.java.test.plugin-*.jar', - }, - ['java-debug'] = { - 'extension/server/com.microsoft.java.debug.plugin-*.jar', - }, - ['spring-boot-tools'] = { 'extension/jars/*.jar' }, -} - function M.get_plugin_version_map(config) return { ['java-test'] = config.java_test.version, @@ -44,22 +13,36 @@ end ---@param plugins string[] ---@return string[] # list of .jar file paths function M.get_plugins(config, plugins) + local file = require('java-core.utils.file') + local List = require('java-core.utils.list') + local Manager = require('pkgm.manager') + local path = require('java-core.utils.path') + local err = require('java-core.utils.errors') + local str = require('java-core.utils.str') + local plugin_version_map = M.get_plugin_version_map(config) return List:new(plugins) :map(function(plugin_name) local version = plugin_version_map[plugin_name] - local root = Manager:get_install_dir(plugin_name, version) - local jars = file.resolve_paths(root, plug_jar_map[plugin_name]) - if #jars == 0 then - -- stylua: ignore - log.error(string.format( 'No jars found for plugin "%s" (version: %s) at %s', plugin_name, version, root)) - -- stylua: ignore - error(string.format( 'Failed to load plugin "%s". No jars found at %s', plugin_name, root)) + local pkg_path = Manager:get_install_dir(plugin_name, version) + local plugin_root = path.join(pkg_path, 'extension') + local package_json_str = vim.fn.readfile(path.join(plugin_root, 'package.json')) + local package_json = vim.json.decode(table.concat(package_json_str, '\n')) + local java_extensions = package_json.contributes.javaExtensions + + local ext_jars = file.resolve_paths(plugin_root, java_extensions) + + if #ext_jars ~= #java_extensions then + err.throw( + str + .multiline('Failed to load some jars for "%s"', 'Expected %d jars but only %d found') + :format(plugin_name, #java_extensions, #ext_jars) + ) end - return jars + return ext_jars end) :flatten() end diff --git a/lua/java-core/utils/errors.lua b/lua/java-core/utils/errors.lua index 65fddb4..9291b1d 100644 --- a/lua/java-core/utils/errors.lua +++ b/lua/java-core/utils/errors.lua @@ -4,11 +4,11 @@ local log = require('java-core.utils.log2') local M = {} ---Notifies user, logs error, and throws error ----@param msg string error message -function M.throw(msg) - notify.error(msg) - log.error(msg) - error(msg) +---@param ... string error message +function M.throw(...) + notify.error(...) + log.error(...) + error(...) end return M diff --git a/lua/java-core/utils/str.lua b/lua/java-core/utils/str.lua new file mode 100644 index 0000000..e9ff7ba --- /dev/null +++ b/lua/java-core/utils/str.lua @@ -0,0 +1,10 @@ +local M = {} + +--- Joins a list of strings with a separator +---@param ... string +---@return string +function M.multiline(...) + return table.concat({ ... }, '\n') +end + +return M diff --git a/lua/java-test/api.lua b/lua/java-test/api.lua index 48fe2b5..93e327a 100644 --- a/lua/java-test/api.lua +++ b/lua/java-test/api.lua @@ -100,7 +100,7 @@ function M:run_test(tests, report, config) local java_exec = self.debug_client:resolve_java_executable(launch_args.mainClass, launch_args.projectName) - log.debug('java executable: ' .. vim.inspect(java_exec)) + log.debug('java executable', java_exec) local dap_launcher_config = dap_adapters.junit_launch_args_to_dap_config(launch_args, java_exec, { debug = true, @@ -109,7 +109,7 @@ function M:run_test(tests, report, config) dap_launcher_config = vim.tbl_deep_extend('force', dap_launcher_config, config or {}) - log.debug('launching tests with config: ' .. vim.inspect(dap_launcher_config)) + log.debug('launching tests with config', dap_launcher_config) self.runner:run_by_config(dap_launcher_config, report) end diff --git a/lua/java/config.lua b/lua/java/config.lua index b42419a..8b65edc 100644 --- a/lua/java/config.lua +++ b/lua/java/config.lua @@ -1,4 +1,4 @@ -local JDTLS_VERSION = '1.43.0' +local JDTLS_VERSION = '1.54.0' local jdtls_version_map = { ['1.43.0'] = { @@ -8,6 +8,13 @@ local jdtls_version_map = { spring_boot_tools = '1.55.1', jdk = '17', }, + ['1.54.0'] = { + lombok = '1.18.42', + java_test = '0.43.2', + java_debug_adapter = '0.58.3', + spring_boot_tools = '1.55.1', + jdk = '25', + }, } local V = jdtls_version_map[JDTLS_VERSION] diff --git a/lua/pkgm/specs/base-spec.lua b/lua/pkgm/specs/base-spec.lua index 817d12d..f97d4ba 100644 --- a/lua/pkgm/specs/base-spec.lua +++ b/lua/pkgm/specs/base-spec.lua @@ -22,7 +22,7 @@ local BaseSpec = class() ---@param config pkgm.BaseSpecConfig function BaseSpec:_init(config) - log.debug('Initializing BaseSpec with config: ' .. vim.inspect(config)) + log.debug('Initializing BaseSpec with config', config) self._name = config.name self._version = config.version @@ -42,7 +42,7 @@ function BaseSpec:_init(config) end end - log.debug('Template vars: ' .. vim.inspect(self._template_vars)) + log.debug('Template vars', self._template_vars) end ---@return string diff --git a/lua/pkgm/specs/init.lua b/lua/pkgm/specs/init.lua index 2396fb1..e92a0cb 100644 --- a/lua/pkgm/specs/init.lua +++ b/lua/pkgm/specs/init.lua @@ -10,7 +10,7 @@ local JdtlsSpec = require('pkgm.specs.jdtls-spec') return { JdtlsSpec({ name = 'jdtls', - version_range = { from = '1.43.0', to = '1.53.0' }, + version_range = { from = '1.43.0', to = '1.54.0' }, url = 'https://download.eclipse.org/{{name}}/milestones/' .. '{{version}}/jdt-language-server-{{version}}-{{timestamp}}.tar.gz', }), @@ -75,4 +75,34 @@ return { }, }, }), + + -- https://download.java.net/java/GA/jdk25.0.1/2fbf10d8c78e40bd87641c434705079d/8/GPL/openjdk-25.0.1_linux-x64_bin.tar.gz + + BaseSpec({ + name = 'openjdk', + version = '25', + urls = { + linux = { + arm = { + ['64bit'] = 'https://download.oracle.com/java/{{version}}/latest/jdk-{{version}}_linux-aarch64_bin.tar.gz', + }, + x86 = { + ['64bit'] = 'https://download.oracle.com/java/{{version}}/latest/jdk-{{version}}_linux-x64_bin.tar.gz', + }, + }, + mac = { + arm = { + ['64bit'] = 'https://download.oracle.com/java/{{version}}/latest/jdk-{{version}}_macos-aarch64_bin.tar.gz', + }, + x86 = { + ['64bit'] = 'https://download.oracle.com/java/{{version}}/latest/jdk-{{version}}_macos-x64_bin.tar.gz', + }, + }, + win = { + x86 = { + ['64bit'] = 'https://download.oracle.com/java/{{version}}/latest/jdk-{{version}}_windows-x64_bin.zip', + }, + }, + }, + }), } diff --git a/lua/pkgm/specs/jdtls-spec/version-map.lua b/lua/pkgm/specs/jdtls-spec/version-map.lua index 62282f9..b5b2cc5 100644 --- a/lua/pkgm/specs/jdtls-spec/version-map.lua +++ b/lua/pkgm/specs/jdtls-spec/version-map.lua @@ -19,4 +19,5 @@ return { ['1.51.0'] = '202510022025', ['1.52.0'] = '202510301627', ['1.53.0'] = '202511192211', + ['1.54.0'] = '202511261751', } diff --git a/tests/constants/capabilities.lua b/tests/constants/capabilities.lua index a7a9d89..fa4572b 100644 --- a/tests/constants/capabilities.lua +++ b/tests/constants/capabilities.lua @@ -9,6 +9,7 @@ M.required_cmds = List:new({ 'java.edit.organizeImports', 'java.edit.smartSemicolonDetection', 'java.edit.stringFormatting', + 'java.getTroubleshootingInfo', 'java.navigate.openTypeHierarchy', 'java.navigate.resolveTypeHierarchy', 'java.project.addToSourcePath', @@ -69,6 +70,7 @@ M.required_cmds = List:new({ 'vscode.java.test.findTestTypesAndMethods', 'vscode.java.test.generateTests', 'vscode.java.test.get.testpath', + 'vscode.java.test.jacoco.getCoverageDetail', 'vscode.java.test.junit.argument', 'vscode.java.test.navigateToTestOrTarget', 'vscode.java.test.resolvePath', diff --git a/tests/specs/capabilities_spec.lua b/tests/specs/capabilities_spec.lua index 1fe36f1..fc0550f 100644 --- a/tests/specs/capabilities_spec.lua +++ b/tests/specs/capabilities_spec.lua @@ -2,7 +2,7 @@ local lsp_utils = dofile('tests/utils/lsp-utils.lua') local capabilities = dofile('tests/constants/capabilities.lua') local List = require('java-core.utils.list') local assert = require('luassert') -local log = require('java-core.utils.log2') +local err = require('java-core.utils.errors') describe('LSP Capabilities', function() it('should have all required commands', function() @@ -21,8 +21,7 @@ describe('LSP Capabilities', function() end) if #extra_cmds > 0 then - log.error('Additional commands found that are not in required list:', extra_cmds) - error('Additional commands found that are not in required list:' .. vim.inspect(extra_cmds)) + err.throw('Additional commands found that are not in required list:', extra_cmds) end end) end)