From 75d1243d0e7c6d2626526afd232039fe90ea09e8 Mon Sep 17 00:00:00 2001 From: Jannik Donker Date: Wed, 22 Apr 2026 20:42:40 +0200 Subject: [PATCH] rewrite and additions --- init.lua | 296 +----------------------------------------------- lua/keymaps.lua | 81 +++++++++++++ lua/lsp.lua | 61 ++++++++++ lua/options.lua | 17 +++ lua/plugins.lua | 99 ++++++++++++++++ 5 files changed, 262 insertions(+), 292 deletions(-) create mode 100644 lua/keymaps.lua create mode 100644 lua/lsp.lua create mode 100644 lua/options.lua create mode 100644 lua/plugins.lua diff --git a/init.lua b/init.lua index 264d00f..7166cf7 100644 --- a/init.lua +++ b/init.lua @@ -1,292 +1,4 @@ --- VIM OPTIONS START -- - -local vim = vim -vim.o.number = true -vim.o.relativenumber = true -vim.o.tabstop = 4 -vim.o.shiftwidth = 4 -vim.o.expandtab = true -vim.o.signcolumn = "yes" -vim.o.swapfile = false -vim.g.mapleader = " " -vim.o.winborder = "single" - --- Make 'j' and 'k' navigate visual lines (not logical lines) -vim.keymap.set("n", "j", "gj", { noremap = true, silent = true }) -vim.keymap.set("n", "k", "gk", { noremap = true, silent = true }) -vim.keymap.set("v", "j", "gj", { noremap = true, silent = true }) -vim.keymap.set("v", "k", "gk", { noremap = true, silent = true }) - --- VIM OPTIONS END -- - --- PLUGINS START -- - -vim.pack.add({ - { src = "https://github.com/ellisonleao/gruvbox.nvim" }, - { src = "https://github.com/stevearc/oil.nvim" }, - { src = "https://github.com/echasnovski/mini.pick" }, - { src = "https://github.com/neovim/nvim-lspconfig" }, - { src = "https://github.com/nvim-treesitter/nvim-treesitter" }, - { src = "https://github.com/nvim-treesitter/nvim-treesitter-textobjects" }, - { src = "https://github.com/Saghen/blink.cmp", version = "v1.7.0" }, - { src = "https://github.com/mason-org/mason.nvim" }, - { src = "https://github.com/nvim-lualine/lualine.nvim.git" }, - { src = "https://github.com/chomosuke/typst-preview.nvim" }, - { src = "https://github.com/numToStr/Comment.nvim" }, - { src = "https://codeberg.org/mfussenegger/nvim-jdtls.git", dependencies = { "https://codeberg.org/mfussenegger/nvim-dap.git" } }, - { src = "https://github.com/m4xshen/autoclose.nvim" }, - { src = "https://codeberg.org/mfussenegger/nvim-dap.git" }, - { src = "https://github.com/romgrk/barbar.nvim" }, - { src = "https://github.com/nvim-tree/nvim-web-devicons" }, - { src = "https://github.com/lewis6991/gitsigns.nvim" }, - { src = "https://github.com/folke/trouble.nvim" }, - { src = "https://github.com/rcarriga/nvim-dap-ui", dependencies = { "https://github.com/mfussenegger/nvim-dap", "https://github.com/nvim-neotest/nvim-nio" } }, - { src = "https://github.com/nvim-neotest/nvim-nio" }, -}) - --- Safely load colorscheme -pcall(vim.cmd, "colorscheme gruvbox") - --- Helper function to safely setup plugins only if they are installed -local function setup_plugin(module, opts) - local ok, plugin = pcall(require, module) - if ok and type(plugin.setup) == "function" then - plugin.setup(opts or {}) - end -end - -setup_plugin("oil") -setup_plugin("mini.pick") -setup_plugin("blink.cmp", { keymap = { preset = "super-tab" } }) --- nvim-treesitter main branch: no configs.setup, no auto_install, --- no highlight.enable. You install parsers and start TS yourself. -local ok_ts, ts = pcall(require, "nvim-treesitter") -if ok_ts then - ts.install({ - "lua", "vim", "vimdoc", "bash", "c", "cpp", "rust", "python", - "javascript", "typescript", "tsx", "svelte", "css", "html", - "json", "toml", "yaml", "markdown", "markdown_inline", - "java", "typst", "vala", - }) -end - -vim.api.nvim_create_autocmd("FileType", { - pattern = "*", - callback = function() - pcall(vim.treesitter.start) - pcall(function() - vim.bo.indentexpr = "v:lua.vim.treesitter.indentexpr()" - end) - end, -}) - -local ok_tot, _ = pcall(require, "nvim-treesitter-textobjects") -if ok_tot then - local select = require("nvim-treesitter-textobjects.select") - vim.keymap.set({ "x", "o" }, "af", function() select.select_textobject("@function.outer", "textobjects") end) - vim.keymap.set({ "x", "o" }, "if", function() select.select_textobject("@function.inner", "textobjects") end) - vim.keymap.set({ "x", "o" }, "ac", function() select.select_textobject("@class.outer", "textobjects") end) - vim.keymap.set({ "x", "o" }, "ic", function() select.select_textobject("@class.inner", "textobjects") end) -end - -setup_plugin("mason") --- Automatically install these tools via Mason -local registry = require("mason-registry") -local ensure_installed = { - "bash-language-server", - "clang-format", - "clangd", - "java-debug-adapter", - "jdtls", - "json-lsp", - "lua-language-server", - "rust-analyzer", - "svelte-language-server", - "tailwindcss-language-server", - "taplo", - "typescript-language-server", - "pylsp", - "black", - "vala" -} - --- Refresh the registry and install missing tools -registry.refresh(function() - for _, tool in ipairs(ensure_installed) do - local ok, pkg = pcall(registry.get_package, tool) - if ok and not pkg:is_installed() then - pkg:install() - end - end -end) - -setup_plugin("lualine", { options = { theme = "gruvbox_dark" } }) -setup_plugin("typst-preview") -setup_plugin("autoclose") -setup_plugin("trouble") -setup_plugin("Comment") - --- PLUGINS END -- - --- DAP START -- - -local ok_dap, dap = pcall(require, "dap") -local ok_dapui, dapui = pcall(require, "dapui") - -if ok_dap and ok_dapui then - dapui.setup() - dap.listeners.before.attach.dapui_config = function() dapui.open() end - dap.listeners.before.launch.dapui_config = function() dapui.open() end -end - --- DAP END -- - --- LSP START -- - --- Assuming vim.lsp.enable is native to your specific Neovim version -vim.lsp.enable({ - "lua_ls", "ts_ls", "svelte", "tailwindcss", "cssls", "bashls", - "rust_analyzer", "clangd", "clang-format", "taplo", - "sourcekit", "lemminx", "tinymist", "jsonls", "hls", "ormolu", "pylsp", "black", "vala_ls" -}) - -vim.lsp.config["sourcekit"] = { - filetypes = { "swift", "objective-c", "objective-c++" } -} - -vim.lsp.config["tinymist"] = { - cmd = { "tinymist" }, - filetypes = { "typst" }, - settings = { - formatterMode = "typstyle", - }, -} - -vim.api.nvim_create_autocmd('FileType', { - pattern = 'java', - callback = function(args) - -- Safely require jdtls so it doesn't crash if uninstalled - local ok, jdtls = pcall(require, "jdtls") - if not ok then return end - - local project_name = vim.fn.fnamemodify(vim.fn.getcwd(), ":p:h:t") - local workspace_dir = vim.fn.stdpath("data") .. - package.config:sub(1, 1) .. "jdtls-workspace" .. package.config:sub(1, 1) .. project_name - local os_name = vim.loop.os_uname().sysname - - local config = { - cmd = { - "java", - "-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", - "-Xmx1g", - "--add-modules=ALL-SYSTEM", - "--add-opens", "java.base/java.util=ALL-UNNAMED", - "--add-opens", "java.base/java.lang=ALL-UNNAMED", - "-jar", - vim.fn.stdpath("data") .. - package.config:sub(1, 1) .. - "mason" .. - package.config:sub(1, 1) .. - "packages" .. - package.config:sub(1, 1) .. - "jdtls" .. - package.config:sub(1, 1) .. - "plugins" .. package.config:sub(1, 1) .. "org.eclipse.equinox.launcher_1.7.100.v20251111-0406.jar", - "-configuration", - vim.fn.stdpath("data") .. - package.config:sub(1, 1) .. - "mason" .. - package.config:sub(1, 1) .. - "packages" .. - package.config:sub(1, 1) .. - "jdtls" .. - package.config:sub(1, 1) .. - "config_" .. (os_name == "Windows_NT" and "win" or os_name == "Linux" and "linux" or "mac"), - "-data", workspace_dir, - }, - root_dir = require("jdtls.setup").find_root({ ".git", "mvnw", "gradlew" }), - settings = { java = {} }, - init_options = { - bundles = { vim.fn.glob("/home/jannikdonker/.local/share/nvim/mason/share/java-debug-adapter/com.microsoft.java.debug.plugin.jar", 1) }, - }, - } - jdtls.start_or_attach(config) - end -}) - --- LSP END -- - --- KEYMAP START -- - -local map = vim.keymap -local opts = { noremap = true, silent = true } - -map.set("n", "gf", vim.lsp.buf.format) -map.set("n", "gd", vim.lsp.buf.definition) -map.set("n", "gD", vim.lsp.buf.declaration) -map.set("n", "ca", vim.lsp.buf.code_action, { desc = "Code Action" }) -map.set("n", "rn", vim.lsp.buf.rename, { desc = "Rename symbol" }) - -map.set("n", "xx", "Trouble diagnostics toggle focus=true", { desc = "Diagnostics (Trouble)" }) -map.set("n", "xX", "Trouble diagnostics toggle filter.buf=0 focus=true", - { desc = "Buffer Diagnostics (Trouble)" }) - -map.set("n", "", ":Pick files") -map.set("n", "", ":Pick grep_live") -map.set("n", "", ":Pick help") -map.set("n", "", ":Oil") - --- Wrapped DAP calls in anonymous functions so they don't evaluate before DAP installs -map.set("n", "duo", function() require("dapui").open() end) -map.set("n", "duc", function() require("dapui").close() end) -map.set("n", "dbp", function() require("dap").toggle_breakpoint() end) -map.set("n", "drc", function() require("dap").run_to_cursor() end) - -local is_mac = vim.fn.has("macunix") == 1 -local barbarKey = is_mac and "M" or "A" - -map.set('n', '<' .. barbarKey .. '-,>', 'BufferPrevious', opts) -map.set('n', '<' .. barbarKey .. '-.>', 'BufferNext', opts) -map.set('n', '<' .. barbarKey .. '-<>', 'BufferMovePrevious', opts) -map.set('n', '<' .. barbarKey .. '->>', 'BufferMoveNext', opts) -map.set('n', '<' .. barbarKey .. '-1>', 'BufferGoto 1', opts) -map.set('n', '<' .. barbarKey .. '-2>', 'BufferGoto 2', opts) -map.set('n', '<' .. barbarKey .. '-3>', 'BufferGoto 3', opts) -map.set('n', '<' .. barbarKey .. '-4>', 'BufferGoto 4', opts) -map.set('n', '<' .. barbarKey .. '-5>', 'BufferGoto 5', opts) -map.set('n', '<' .. barbarKey .. '-6>', 'BufferGoto 6', opts) -map.set('n', '<' .. barbarKey .. '-7>', 'BufferGoto 7', opts) -map.set('n', '<' .. barbarKey .. '-8>', 'BufferGoto 8', opts) -map.set('n', '<' .. barbarKey .. '-9>', 'BufferGoto 9', opts) -map.set('n', '<' .. barbarKey .. '-0>', 'BufferLast', opts) -map.set('n', '<' .. barbarKey .. '-p>', 'BufferPin', opts) -map.set('n', '<' .. barbarKey .. '-w>', 'BufferClose', opts) -map.set('n', '', 'BufferPick', opts) -map.set('n', '', 'BufferPickDelete', opts) - --- KEYMAP END -- - -vim.diagnostic.config({ - virtual_text = { - prefix = "●", - spacing = 2, - source = "if_many", - }, - severity_sort = true, -}) - -vim.keymap.set("n", "sc", function() - vim.wo.spell = not vim.wo.spell - print("Spell checking: " .. (vim.wo.spell and "ON" or "OFF")) -end, { desc = "Toggle spell checking" }) - -vim.keymap.set("n", "sl", function() - local current = vim.opt.spelllang:get()[1] or "" - local new_lang = current == "en" and "de" or "en" - vim.opt.spelllang = new_lang - print("Spell language: " .. new_lang) -end, { desc = "Switch spell language" }) +require("options") +require("plugins") +require("lsp") +require("keymaps") diff --git a/lua/keymaps.lua b/lua/keymaps.lua new file mode 100644 index 0000000..5e687bd --- /dev/null +++ b/lua/keymaps.lua @@ -0,0 +1,81 @@ +local map = vim.keymap.set +local silent = { silent = true } + +-- Visual line navigation +for _, mode in ipairs({ "n", "v" }) do + map(mode, "j", "gj", silent) + map(mode, "k", "gk", silent) +end + +-- Hover: diagnostics on current line if any, else LSP hover +map("n", "K", function() + local line = vim.api.nvim_win_get_cursor(0)[1] - 1 + if #vim.diagnostic.get(0, { lnum = line }) > 0 then + vim.diagnostic.open_float() + else + vim.lsp.buf.hover() + end +end, { desc = "Hover (diagnostic or LSP)" }) + +-- LSP +map("n", "gf", + function() require("conform").format({ lsp_format = "fallback" }) end, + { desc = "Format buffer" }) +map("n", "gd", vim.lsp.buf.definition) +map("n", "gD", vim.lsp.buf.declaration) +map("n", "ca", vim.lsp.buf.code_action, { desc = "Code Action" }) +map("n", "rn", vim.lsp.buf.rename, { desc = "Rename symbol" }) + +-- Trouble +map("n", "xx", "Trouble diagnostics toggle focus=true", + { desc = "Diagnostics (Trouble)" }) +map("n", "xX", "Trouble diagnostics toggle filter.buf=0 focus=true", + { desc = "Buffer Diagnostics (Trouble)" }) +map("n", "xt", "Trouble todo toggle", { desc = "Todo (Trouble)" }) + +-- Flash +map({ "n", "x", "o" }, "s", function() require("flash").jump() end, { desc = "Flash" }) +map({ "n", "x", "o" }, "S", function() require("flash").treesitter() end, { desc = "Flash Treesitter" }) +map("o", "r", function() require("flash").remote() end, { desc = "Remote Flash" }) + +-- Pickers / files +map("n", "", "Pick files") +map("n", "", "Pick grep_live") +map("n", "", "Pick help") +map("n", "", "Oil") + +-- DAP +map("n", "duo", function() require("dapui").open() end) +map("n", "duc", function() require("dapui").close() end) +map("n", "dbp", function() require("dap").toggle_breakpoint() end) +map("n", "drc", function() require("dap").run_to_cursor() end) + +-- Barbar +local bk = vim.fn.has("macunix") == 1 and "M" or "A" +local bar = { + [","] = "BufferPrevious", ["."] = "BufferNext", + ["<"] = "BufferMovePrevious", [">"] = "BufferMoveNext", + ["p"] = "BufferPin", ["w"] = "BufferClose", + ["0"] = "BufferLast", +} +for k, cmd in pairs(bar) do + map("n", ("<%s-%s>"):format(bk, k), ("%s"):format(cmd), silent) +end +for i = 1, 9 do + map("n", ("<%s-%d>"):format(bk, i), ("BufferGoto %d"):format(i), silent) +end +map("n", "", "BufferPick", silent) +map("n", "", "BufferPickDelete", silent) + +-- Spell +map("n", "sc", function() + vim.wo.spell = not vim.wo.spell + vim.notify("Spell: " .. (vim.wo.spell and "ON" or "OFF")) +end, { desc = "Toggle spell" }) + +map("n", "sl", function() + local cur = vim.opt.spelllang:get()[1] or "" + local new = cur == "en" and "de" or "en" + vim.opt.spelllang = new + vim.notify("Spell lang: " .. new) +end, { desc = "Switch spell language" }) diff --git a/lua/lsp.lua b/lua/lsp.lua new file mode 100644 index 0000000..f941b9b --- /dev/null +++ b/lua/lsp.lua @@ -0,0 +1,61 @@ +-- Per-server overrides +vim.lsp.config("sourcekit", { + filetypes = { "swift", "objective-c", "objective-c++" }, +}) + +vim.lsp.config("tinymist", { + cmd = { "tinymist" }, + filetypes = { "typst" }, + settings = { formatterMode = "typstyle" }, +}) + +vim.lsp.enable({ + "lua_ls", "ts_ls", "svelte", "tailwindcss", "cssls", "bashls", + "rust_analyzer", "clangd", "taplo", "sourcekit", "lemminx", + "tinymist", "jsonls", "hls", "pylsp", "vala_ls", +}) + +-- JDTLS (managed manually because it needs per-project workspace) +vim.api.nvim_create_autocmd("FileType", { + pattern = "java", + callback = function() + local jdtls = require("jdtls") + local data = vim.fn.stdpath("data") + local mason_jdtls = vim.fs.joinpath(data, "mason", "packages", "jdtls") + local workspace = vim.fs.joinpath(data, "jdtls-workspace", + vim.fn.fnamemodify(vim.fn.getcwd(), ":p:h:t")) + local sys = vim.uv.os_uname().sysname + local cfg_dir = sys == "Windows_NT" and "config_win" + or sys == "Linux" and "config_linux" + or "config_mac" + + local launcher = vim.fn.glob(vim.fs.joinpath( + mason_jdtls, "plugins", "org.eclipse.equinox.launcher_*.jar")) + + jdtls.start_or_attach({ + cmd = { + "java", + "-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", + "-Xmx1g", + "--add-modules=ALL-SYSTEM", + "--add-opens", "java.base/java.util=ALL-UNNAMED", + "--add-opens", "java.base/java.lang=ALL-UNNAMED", + "-jar", launcher, + "-configuration", vim.fs.joinpath(mason_jdtls, cfg_dir), + "-data", workspace, + }, + root_dir = vim.fs.root(0, { ".git", "mvnw", "gradlew" }), + settings = { java = {} }, + init_options = { + bundles = { + vim.fn.glob(vim.fs.joinpath(data, "mason", "share", + "java-debug-adapter", "com.microsoft.java.debug.plugin.jar")), + }, + }, + }) + end, +}) diff --git a/lua/options.lua b/lua/options.lua new file mode 100644 index 0000000..6e52350 --- /dev/null +++ b/lua/options.lua @@ -0,0 +1,17 @@ +vim.g.mapleader = " " + +local o = vim.o +o.number = true +o.relativenumber = true +o.tabstop = 4 +o.shiftwidth = 4 +o.expandtab = true +o.signcolumn = "yes" +o.swapfile = false +o.winborder = "single" +o.termguicolors = true + +vim.diagnostic.config({ + virtual_text = { prefix = "●", spacing = 2, source = "if_many" }, + severity_sort = true, +}) diff --git a/lua/plugins.lua b/lua/plugins.lua new file mode 100644 index 0000000..41e7ee8 --- /dev/null +++ b/lua/plugins.lua @@ -0,0 +1,99 @@ +vim.pack.add({ + { src = "https://github.com/ellisonleao/gruvbox.nvim" }, + { src = "https://github.com/stevearc/oil.nvim" }, + { src = "https://github.com/echasnovski/mini.pick" }, + { src = "https://github.com/neovim/nvim-lspconfig" }, + { src = "https://github.com/nvim-treesitter/nvim-treesitter" }, + { src = "https://github.com/nvim-treesitter/nvim-treesitter-textobjects" }, + { src = "https://github.com/Saghen/blink.cmp", version = "v1.7.0" }, + { src = "https://github.com/mason-org/mason.nvim" }, + { src = "https://github.com/nvim-lualine/lualine.nvim.git" }, + { src = "https://github.com/chomosuke/typst-preview.nvim" }, + { src = "https://codeberg.org/mfussenegger/nvim-jdtls.git" }, + { src = "https://github.com/windwp/nvim-autopairs" }, + { src = "https://codeberg.org/mfussenegger/nvim-dap.git" }, + { src = "https://github.com/romgrk/barbar.nvim" }, + { src = "https://github.com/nvim-tree/nvim-web-devicons" }, + { src = "https://github.com/echasnovski/mini.ai" }, + { src = "https://github.com/windwp/nvim-ts-autotag" }, + { src = "https://github.com/folke/todo-comments.nvim" }, + { src = "https://github.com/stevearc/conform.nvim" }, + { src = "https://github.com/folke/flash.nvim" }, + { src = "https://github.com/lewis6991/gitsigns.nvim" }, + { src = "https://github.com/folke/trouble.nvim" }, + { src = "https://github.com/nvim-neotest/nvim-nio" }, + { src = "https://github.com/rcarriga/nvim-dap-ui" }, +}) + +pcall(vim.cmd.colorscheme, "gruvbox") + +-- Simple setup({}) plugins +for _, name in ipairs({ + "oil", "mini.pick", "mason", "typst-preview", "nvim-autopairs", + "trouble", "gitsigns", "nvim-web-devicons", "barbar", + "mini.ai", "nvim-ts-autotag", "todo-comments", "flash", +}) do + pcall(function() require(name).setup() end) +end + +require("conform").setup({ + formatters_by_ft = { + python = { "black" }, + c = { "clang-format" }, + cpp = { "clang-format" }, + java = { "clang-format" }, + javascript = { "prettierd", "prettier", stop_after_first = true }, + typescript = { "prettierd", "prettier", stop_after_first = true }, + svelte = { "prettierd", "prettier", stop_after_first = true }, + css = { "prettierd", "prettier", stop_after_first = true }, + html = { "prettierd", "prettier", stop_after_first = true }, + json = { "prettierd", "prettier", stop_after_first = true }, + }, + format_on_save = { timeout_ms = 500, lsp_format = "fallback" }, +}) + +require("lualine").setup({ options = { theme = "gruvbox_dark" } }) +require("blink.cmp").setup({ keymap = { preset = "super-tab" } }) + +-- Treesitter (main branch: no configs.setup; install parsers manually) +require("nvim-treesitter").install({ + "lua", "vim", "vimdoc", "bash", "c", "cpp", "rust", "python", + "javascript", "typescript", "tsx", "svelte", "css", "html", + "json", "toml", "yaml", "markdown", "markdown_inline", + "java", "typst", "vala", +}) + +vim.api.nvim_create_autocmd("FileType", { + callback = function() pcall(vim.treesitter.start) end, +}) + +-- TS textobjects +local tso = require("nvim-treesitter-textobjects.select") +local textobj = { af = "@function.outer", ["if"] = "@function.inner", + ac = "@class.outer", ic = "@class.inner" } +for lhs, query in pairs(textobj) do + vim.keymap.set({ "x", "o" }, lhs, + function() tso.select_textobject(query, "textobjects") end) +end + +-- Mason: ensure tools +local registry = require("mason-registry") +local ensure = { + "bash-language-server", "clang-format", "clangd", "java-debug-adapter", + "jdtls", "json-lsp", "lua-language-server", "rust-analyzer", + "svelte-language-server", "tailwindcss-language-server", "taplo", + "typescript-language-server", "pylsp", "black", "vala", + "prettierd", +} +registry.refresh(function() + for _, tool in ipairs(ensure) do + local ok, pkg = pcall(registry.get_package, tool) + if ok and not pkg:is_installed() then pkg:install() end + end +end) + +-- DAP UI wiring +local dap, dapui = require("dap"), require("dapui") +dapui.setup() +dap.listeners.before.attach.dapui_config = function() dapui.open() end +dap.listeners.before.launch.dapui_config = function() dapui.open() end