diff --git a/home/programs/nvim.nix b/home/programs/nvim.nix index eee3a89..4d35165 100644 --- a/home/programs/nvim.nix +++ b/home/programs/nvim.nix @@ -7,11 +7,6 @@ vimAlias = true; defaultEditor = true; - extraPackages = with pkgs; [ - jdtls - jdk - ]; - initLua = '' vim.opt.number = true vim.opt.relativenumber = true @@ -91,30 +86,94 @@ }, }) - local lspconfig = require('lspconfig') + -- Java indentation must match Eclipse's formatter, not your 2-space default. + vim.api.nvim_create_autocmd("FileType", { + pattern = "java", + callback = function() + vim.bo.expandtab = false + vim.bo.tabstop = 4 + vim.bo.shiftwidth = 4 + vim.bo.softtabstop = 4 + end, + }) - -- Common keymaps to run when the Eclipse LSP attaches to a Java buffer - local on_attach = function(client, bufnr) - local opts = { buffer = bufnr, silent = true } - - -- Eclipse IDE core features mapped to Neovim actions - vim.keymap.set('n', 'gD', vim.lsp.buf.declaration, opts) - vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts) - vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts) - vim.keymap.set('n', 'gi', vim.lsp.buf.implementation, opts) - vim.keymap.set('n', '', vim.lsp.buf.signature_help, opts) - vim.keymap.set('n', 'rn', vim.lsp.buf.rename, opts) - vim.keymap.set('n', 'ca', vim.lsp.buf.code_action, opts) - vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts) - vim.keymap.set('n', 'f', function() vim.lsp.buf.format { async = true } end, opts) + local cmp = require("cmp") + local luasnip = require("luasnip") + cmp.setup({ + snippet = { expand = function(a) luasnip.lsp_expand(a.body) end }, + mapping = cmp.mapping.preset.insert({ + [""] = cmp.mapping.complete(), + [""] = cmp.mapping.confirm({ select = false }), + [""] = cmp.mapping.select_next_item(), + [""] = cmp.mapping.select_prev_item(), + }), + sources = { + { name = "nvim_lsp" }, + { name = "luasnip" }, + { name = "buffer" }, + { name = "path" }, + }, + }) + + local capabilities = require("cmp_nvim_lsp").default_capabilities() + + -- .project and .classpath come first so a repo containing several + -- assignments resolves to the assignment, not the repo root. + local root_markers = { ".project", ".classpath", "pom.xml", "build.gradle", ".git" } + + local function start_jdtls() + local jdtls = require("jdtls") + local root_dir = require("jdtls.setup").find_root(root_markers) + if not root_dir or root_dir == "" then return end + + local project_name = vim.fn.fnamemodify(root_dir, ":p:h:t") + local workspace = vim.fn.stdpath("cache") .. "/jdtls-workspaces/" .. project_name + + local java_settings = { + configuration = { + updateBuildConfiguration = "interactive", + runtimes = { + { name = "JavaSE-21", path = os.getenv("JAVA_HOME"), default = true }, + }, + }, + -- Keep a stray pom.xml from overriding the Eclipse project model. + -- Flip these on if a course actually requires Maven or Gradle. + import = { + maven = { enabled = false }, + gradle = { enabled = false }, + }, + signatureHelp = { enabled = true }, + eclipse = { downloadSources = true }, + } + + -- If the repo carries an exported Eclipse formatter profile, use it verbatim. + local formatter = root_dir .. "/.settings/eclipse-formatter.xml" + if vim.uv.fs_stat(formatter) then + java_settings.format = { settings = { url = formatter } } + end + + jdtls.start_or_attach({ + cmd = { "jdtls", "-data", workspace }, + root_dir = root_dir, + capabilities = capabilities, + settings = { java = java_settings }, + init_options = { bundles = {} }, + on_attach = function(_, bufnr) + local map = function(k, f) vim.keymap.set("n", k, f, { buffer = bufnr, silent = true }) end + map("gd", vim.lsp.buf.definition) + map("gr", vim.lsp.buf.references) + map("K", vim.lsp.buf.hover) + map("rn", vim.lsp.buf.rename) + map("ca", vim.lsp.buf.code_action) + map("f", function() vim.lsp.buf.format({ async = true }) end) + map("oi", require("jdtls").organize_imports) + end, + }) end - -- Initialize the Eclipse JDTLS Server configuration - -- NixOS patches 'jdtls' wrapper script automatically to point to the correct binary paths - lspconfig.jdtls.setup({ - on_attach = on_attach, - cmd = { "jdtls" }, - root_dir = lspconfig.util.root_pattern(".git", "pom.xml", "build.gradle"), + vim.api.nvim_create_autocmd("FileType", { + pattern = "java", + callback = start_jdtls, }) ''; @@ -126,7 +185,15 @@ { plugin = lualine-nvim; } { plugin = neocord; } { plugin = gitsigns-nvim; } - { plugin = nvim-lspconfig; } + + { plugin = nvim-jdtls; } + { plugin = nvim-cmp; } + { plugin = cmp-nvim-lsp; } + { plugin = cmp-buffer; } + { plugin = cmp-path; } + { plugin = luasnip; } + { plugin = cmp_luasnip; } + { plugin = (nvim-treesitter.withPlugins (p: [ p.java p.xml p.nix p.lua ])); } ]; }; } diff --git a/system/packages.nix b/system/packages.nix index 03c3878..9de24ca 100644 --- a/system/packages.nix +++ b/system/packages.nix @@ -22,7 +22,10 @@ ]; }) google-chrome + google-java-format gnupg + jdk + jdt-language-server jq keepassxc lan-mouse