diff --git a/init.lua b/init.lua index b98ffc6198a..491276f8cda 100644 --- a/init.lua +++ b/init.lua @@ -683,7 +683,7 @@ require('lazy').setup({ -- But for many setups, the LSP (`ts_ls`) will work just fine -- ts_ls = {}, -- - + jdtls = {}, lua_ls = { -- cmd = { ... }, -- filetypes = { ... }, @@ -722,6 +722,11 @@ require('lazy').setup({ require('mason-lspconfig').setup { ensure_installed = {}, -- explicitly set to an empty table (Kickstart populates installs via mason-tool-installer) automatic_installation = false, + automatic_enable = { + exclude = { + 'jdtls', + }, + }, handlers = { function(server_name) local server = servers[server_name] or {} @@ -777,6 +782,10 @@ require('lazy').setup({ }, }, + { + 'mfussenegger/nvim-jdtls', + }, + { -- Autocompletion 'saghen/blink.cmp', event = 'VimEnter', @@ -1012,5 +1021,13 @@ require('lazy').setup({ }, }) --- The line beneath this is called `modeline`. See `:help modeline` +vim.api.nvim_create_autocmd('FileType', { + pattern = 'java', + callback = function() + vim.opt_local.tabstop = 2 + vim.opt_local.shiftwidth = 2 + + require('lsp.jdtls').setup() + end, +}) -- The line beneath this is called `modeline`. See `:help modeline` -- vim: ts=2 sts=2 sw=2 et diff --git a/lua/lsp/jdtls.lua b/lua/lsp/jdtls.lua new file mode 100644 index 00000000000..4301ce72ef9 --- /dev/null +++ b/lua/lsp/jdtls.lua @@ -0,0 +1,98 @@ +local M = {} + +function M.setup() + local home = os.getenv 'HOME' + local workspace_path = home .. '/.local/share/nvim/jdtls-workspace/' + local project_name = vim.fn.fnamemodify(vim.fn.getcwd(), ':p:h:t') + local workspace_dir = workspace_path .. project_name + + local status, jdtls = pcall(require, 'jdtls') + if not status then + vim.notify('jdtls not found!', vim.log.levels.ERROR) + return + end + + local extendedClientCapabilities = jdtls.extendedClientCapabilities + + -- Root markers for Java project + local root_markers = { '.git', 'mvnw', 'gradlew', 'pom.xml', 'build.gradle' } + + local function find_root_dir() + local parent_dir = vim.fn.fnamemodify(vim.fn.getcwd(), ':h') + local root = jdtls.setup.find_root(root_markers, parent_dir) + if not root or root == '' then + root = jdtls.setup.find_root(root_markers) + end + return root or vim.fn.getcwd() + end + + -- Java executable (Java 25, macOS) + local java_exe = '/Library/Java/JavaVirtualMachines/temurin-25.jdk/Contents/Home/bin/java' + + local config = { + cmd = { + java_exe, + '-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', + '-Xmx2g', + '--add-modules=ALL-SYSTEM', + '--add-opens', + 'java.base/java.util=ALL-UNNAMED', + '--add-opens', + 'java.base/java.lang=ALL-UNNAMED', + '-javaagent:' .. home .. '/.local/share/nvim/mason/packages/jdtls/lombok.jar', + '-jar', + vim.fn.glob(home .. '/.local/share/nvim/mason/packages/jdtls/plugins/org.eclipse.equinox.launcher_*.jar'), + '-configuration', + home .. '/.local/share/nvim/mason/packages/jdtls/config_mac', + '-data', + workspace_dir, + }, + + root_dir = find_root_dir(), + + settings = { + java = { + signatureHelp = { enabled = true }, + extendedClientCapabilities = extendedClientCapabilities, + maven = { downloadSources = true }, + referencesCodeLens = { enabled = true }, + references = { includeDecompiledSources = true }, + inlayHints = { parameterNames = { enabled = 'all' } }, + format = { enabled = false }, + saveActions = { organizeImports = false }, + }, + }, + + init_options = { + bundles = {}, + }, + } + + -- Start or attach jdtls + jdtls.start_or_attach(config) + + -------------------------------------------------------------------- + -- Keymaps + -------------------------------------------------------------------- + local opts = { noremap = true, silent = true } + + vim.keymap.set('n', 'jo', "lua require'jdtls'.organize_imports()", { desc = 'Organize Imports' }) + vim.keymap.set('n', 'jrv', "lua require('jdtls').extract_variable()", { desc = 'Extract Variable' }) + vim.keymap.set('v', 'jrv', "lua require('jdtls').extract_variable(true)", { desc = 'Extract Variable' }) + vim.keymap.set('n', 'jrc', "lua require('jdtls').extract_constant()", { desc = 'Extract Constant' }) + vim.keymap.set('v', 'jrc', "lua require('jdtls').extract_constant(true)", { desc = 'Extract Constant' }) + vim.keymap.set('v', 'jrm', "lua require('jdtls').extract_method(true)", { desc = 'Extract Method' }) + vim.keymap.set('n', 'nd', vim.lsp.buf.definition, { desc = 'Go to Definition' }) + vim.keymap.set('n', 'nD', vim.lsp.buf.declaration, { desc = 'Go to Declaration' }) + vim.keymap.set('n', 'nr', vim.lsp.buf.references, { desc = 'References' }) + vim.keymap.set('n', 'ni', vim.lsp.buf.implementation, { desc = 'Go to Implementation' }) + vim.keymap.set('n', 'K', vim.lsp.buf.hover, { desc = 'Hover Documentation' }) + vim.keymap.set('n', 'rn', vim.lsp.buf.rename, { desc = 'Rename Symbol' }) + vim.keymap.set('n', 'ca', vim.lsp.buf.code_action, { desc = 'Code Action' }) +end + +return M