Files
.dotfiles/home/programs/nvim.nix
T

278 lines
9.3 KiB
Nix

{ config, pkgs, ... }:
let
javaDebug = pkgs.vscode-extensions.vscjava.vscode-java-debug;
in
{
programs.neovim = {
enable = true;
viAlias = true;
vimAlias = true;
defaultEditor = true;
initLua = ''
vim.opt.number = true
vim.opt.relativenumber = true
vim.opt.tabstop = 2
vim.opt.softtabstop = 2
vim.opt.expandtab = true
vim.opt.shiftwidth = 2
vim.opt.smartindent = true
vim.opt.wrap = false
vim.opt.swapfile = false
vim.opt.backup = false
vim.opt.undofile = false
vim.opt.hlsearch = false
vim.opt.incsearch = true
vim.opt.termguicolors = true
vim.opt.clipboard = "unnamedplus"
vim.opt.scrolloff = 999
vim.opt.updatetime = 50
vim.opt.foldmethod = "indent"
vim.opt.foldlevel = 99
vim.g.mapleader = " "
vim.keymap.set("n", "<leader>w", "<cmd>w<CR>", { silent = true })
vim.keymap.set("n", "<leader>q", "<cmd>q<CR>", { silent = true })
vim.keymap.set("n", "<leader>wq", "<cmd>wq<CR>", { silent = true })
vim.keymap.set("n", "<leader>x", "<cmd>!chmod +x %<CR>", { silent = true })
vim.keymap.set("n", "Q", "<nop>")
vim.keymap.set("n", "o", "o<esc>")
vim.keymap.set("n", "O", "O<esc>")
vim.keymap.set("i", "jj", "<esc>")
local is_dark = vim.o.background ~= "light"
require("cyberdream").setup({
transparent = is_dark,
variant = is_dark and "dark" or "light",
terminal_colors = true,
})
vim.cmd.colorscheme("cyberdream")
require("nvim-tree").setup({
view = { width = 30 },
renderer = { group_empty = true },
filters = { dotfiles = false },
})
require("bufferline").setup({
options = {
offsets = {
{
filetype = "NvimTree",
text = "Files",
highlight = "Directory",
separator = true,
},
},
},
})
require("lualine").setup({
options = { theme = "auto" },
})
require("neocord").setup({
logo = "auto",
logo_tooltip = "Neovim",
main_image = "language",
show_time = true,
global_timer = true,
})
require("gitsigns").setup({
signs = {
add = { text = "+" },
change = { text = "~" },
delete = { text = "_" },
},
})
-- nvim-treesitter no longer exposes a configs module; highlighting is
-- started per buffer. Indent is deliberately left alone so treesitter
-- doesn't fight the Eclipse-matching tab settings below.
vim.api.nvim_create_autocmd("FileType", {
pattern = { "java", "xml", "nix", "lua" },
callback = function(args)
pcall(vim.treesitter.start, args.buf)
end,
})
-- Java indentation must match Eclipse's formatter, not the 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,
})
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({
["<C-Space>"] = cmp.mapping.complete(),
["<CR>"] = cmp.mapping.confirm({ select = false }),
["<C-n>"] = cmp.mapping.select_next_item(),
["<C-p>"] = cmp.mapping.select_prev_item(),
}),
sources = {
{ name = "nvim_lsp" },
{ name = "luasnip" },
{ name = "buffer" },
{ name = "path" },
},
})
local capabilities = require("cmp_nvim_lsp").default_capabilities()
local bundles = vim.fn.glob(
"${javaDebug}/share/vscode/extensions/vscjava.vscode-java-debug/server/com.microsoft.java.debug.plugin-*.jar",
true, true)
if #bundles == 0 then
vim.notify("java-debug bundle not found - Java debugging disabled", vim.log.levels.WARN)
end
local java_home = os.getenv("JAVA_HOME")
if not java_home then
local javac = vim.fn.exepath("javac")
if javac ~= "" then
java_home = vim.fn.fnamemodify(vim.fn.resolve(javac), ":h:h")
end
end
if not java_home then
vim.notify("No JAVA_HOME and no javac on PATH - jdtls will guess a runtime", vim.log.levels.WARN)
end
if not java_home then
vim.notify("JAVA_HOME unset - jdtls will guess a runtime", vim.log.levels.WARN)
end
-- Eclipse metadata wins over build files, build files over .git, and the
-- file's own directory is the last resort so bare folders still attach.
local function find_project_root()
local setup = require("jdtls.setup")
return setup.find_root({ ".project", ".classpath" })
or setup.find_root({ "pom.xml", "build.gradle", "build.gradle.kts" })
or setup.find_root({ ".git" })
or vim.fn.expand("%:p:h")
end
local dap_configured = false
local function start_jdtls()
local jdtls = require("jdtls")
local root_dir = find_project_root()
local project_name = vim.fn.fnamemodify(root_dir, ":p:h:t")
.. "-" .. vim.fn.sha256(root_dir):sub(1, 8)
local workspace = vim.fn.stdpath("cache") .. "/jdtls-workspaces/" .. project_name
local java_settings = {
configuration = {
updateBuildConfiguration = "automatic",
},
-- 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 },
},
project = {
outputPath = "bin",
referencedLibraries = { "lib/**/*.jar" },
},
signatureHelp = { enabled = true },
eclipse = { downloadSources = true },
}
if java_home then
java_settings.configuration.runtimes = {
{ name = "JavaSE-21", path = java_home, default = true },
}
end
-- 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 = bundles },
on_attach = function(_, bufnr)
require("jdtls").setup_dap({ hotcodereplace = "auto" })
if not dap_configured then
dap_configured = true
require("jdtls.dap").setup_dap_main_class_configs()
end
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("<leader>rn", vim.lsp.buf.rename)
map("<leader>ca", vim.lsp.buf.code_action)
map("<leader>f", function() vim.lsp.buf.format({ async = true }) end)
map("<leader>oi", require("jdtls").organize_imports)
end,
})
end
vim.api.nvim_create_autocmd("FileType", {
pattern = "java",
callback = start_jdtls,
})
local dap, dapui = require("dap"), require("dapui")
dapui.setup()
require("nvim-dap-virtual-text").setup()
dap.listeners.after.event_initialized["dapui"] = function() dapui.open() end
dap.listeners.before.event_terminated["dapui"] = function() dapui.close() end
dap.listeners.before.event_exited["dapui"] = function() dapui.close() end
vim.keymap.set("n", "<leader>db", dap.toggle_breakpoint)
vim.keymap.set("n", "<leader>dB", function()
dap.set_breakpoint(vim.fn.input("Condition: "))
end)
vim.keymap.set("n", "<leader>dc", dap.continue)
vim.keymap.set("n", "<leader>dn", dap.step_over)
vim.keymap.set("n", "<leader>di", dap.step_into)
vim.keymap.set("n", "<leader>du", dap.step_out)
vim.keymap.set("n", "<leader>dr", dap.repl.toggle)
vim.keymap.set("n", "<leader>dq", dap.terminate)
vim.keymap.set({ "n", "v" }, "<leader>de", function() dapui.eval() end)
'';
plugins = with pkgs.vimPlugins; [
{ plugin = cyberdream-nvim; }
{ plugin = nvim-web-devicons; }
{ plugin = nvim-tree-lua; }
{ plugin = bufferline-nvim; }
{ plugin = lualine-nvim; }
{ plugin = neocord; }
{ plugin = gitsigns-nvim; }
{ plugin = nvim-jdtls; }
{ plugin = nvim-dap; }
{ plugin = nvim-dap-ui; }
{ plugin = nvim-nio; }
{ plugin = nvim-dap-virtual-text; }
{ 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 ])); }
];
};
}