local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" if not vim.loop.fs_stat(lazypath) then vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", "--branch=stable", lazypath, }) end vim.opt.rtp:prepend(lazypath) -- Basic Options vim.g.mapleader = " " vim.wo.number = true vim.opt.tabstop = 2 vim.opt.softtabstop = 2 vim.opt.shiftwidth = 2 vim.opt.autoindent = true vim.opt.smartindent = true vim.opt.termguicolors = true vim.opt.expandtab = true vim.opt.clipboard = "unnamedplus" -- Use system clipboard if vim.fn.has("win32") == 1 then vim.g.clipboard = { name = "win32yank", copy = { ["+"] = "win32yank.exe -i --crlf", ["*"] = "win32yank.exe -i --crlf", }, paste = { ["+"] = "win32yank.exe -o --lf", ["*"] = "win32yank.exe -o --lf", }, cache_enabled = 0, } end vim.opt.ignorecase = true vim.opt.smartcase = true -- Keymaps (Global) local options = { noremap = true, silent = true } vim.keymap.set("i", "jk", "", options) -- Clipboard Mappings (IDE Style) vim.keymap.set("v", "", '"+y', { desc = "Copy to clipboard" }) vim.keymap.set("v", "", '"+d', { desc = "Cut to clipboard" }) vim.keymap.set("n", "", '"+p', { desc = "Paste from clipboard" }) vim.keymap.set("i", "", "+", { desc = "Paste from clipboard" }) vim.keymap.set("c", "", "+", { desc = "Paste from clipboard" }) vim.keymap.set("t", "", [["+pa]], { desc = "Paste from clipboard" }) if vim.g.vscode then -- VS Code specific settings/keymaps could go here else -- Highlight on yank vim.api.nvim_create_autocmd("textyankpost", { group = vim.api.nvim_create_augroup("highlight_yank", {}), desc = "Highlight selection on yank", pattern = "*", callback = function() vim.highlight.on_yank({ higroup = "incsearch", timeout = 500 }) end, }) require("lazy").setup({ -- UI & Utilities { "folke/which-key.nvim", event = "VeryLazy", init = function() vim.o.timeout = true vim.o.timeoutlen = 300 end, opts = {}, }, { "folke/trouble.nvim", dependencies = { "nvim-tree/nvim-web-devicons" } }, { "nvim-tree/nvim-web-devicons" }, { "folke/neodev.nvim", opts = {} }, -- Better Lua dev experience -- Git { "kdheepak/lazygit.nvim", dependencies = { "nvim-lua/plenary.nvim" } }, { "lewis6991/gitsigns.nvim", dependencies = { "nvim-lua/plenary.nvim" } }, { "tpope/vim-rhubarb" }, { "tommcdo/vim-fubitive" }, { "theprimeagen/git-worktree.nvim" }, { "neogitorg/neogit", dependencies = { "nvim-lua/plenary.nvim", "sindrets/diffview.nvim", "nvim-telescope/telescope.nvim", }, config = true, }, -- Java Environment { "mfussenegger/nvim-jdtls", dependencies = { "mfussenegger/nvim-dap" } }, -- Debugging UI { "rcarriga/nvim-dap-ui", dependencies = { "mfussenegger/nvim-dap", "nvim-neotest/nvim-nio" }, config = function() require("dapui").setup() local dap, dapui = require("dap"), require("dapui") dap.listeners.after.event_initialized["dapui_config"] = function() dapui.open() end dap.listeners.before.event_terminated["dapui_config"] = function() dapui.close() end dap.listeners.before.event_exited["dapui_config"] = function() dapui.close() end end, }, -- LSP & Completion (The Modern Stack) { "williamboman/mason.nvim", dependencies = { "WhoIsSethDaniel/mason-tool-installer.nvim", }, config = function() require("mason").setup() require("mason-tool-installer").setup({ ensure_installed = { "black", "isort", "prettierd", "stylua", "google-java-format", "eslint_d", -- for nvim-lint "pylint", -- for nvim-lint }, }) end, }, { "williamboman/mason-lspconfig.nvim", dependencies = { "williamboman/mason.nvim" }, config = function() local capabilities = require("cmp_nvim_lsp").default_capabilities() local lspconfig = require("lspconfig") require("mason-lspconfig").setup({ ensure_installed = { "lua_ls", "jdtls" }, automatic_installation = true, handlers = { function(server_name) if server_name == "jdtls" then -- JDTLS is handled by nvim-jdtls via autocommand below else lspconfig[server_name].setup({ capabilities = capabilities, }) end end, }, }) end, }, { "neovim/nvim-lspconfig" }, { "hrsh7th/nvim-cmp", dependencies = { "hrsh7th/cmp-nvim-lsp", "hrsh7th/cmp-nvim-lua", "hrsh7th/cmp-buffer", "hrsh7th/cmp-cmdline", "saadparwaiz1/cmp_luasnip", "l3mon4d3/luasnip", }, config = function() local cmp = require("cmp") local luasnip = require("luasnip") cmp.setup({ snippet = { expand = function(args) luasnip.lsp_expand(args.body) end, }, window = { completion = cmp.config.window.bordered(), documentation = cmp.config.window.bordered(), }, mapping = cmp.mapping.preset.insert({ [""] = cmp.mapping.scroll_docs(-4), [""] = cmp.mapping.scroll_docs(4), [""] = cmp.mapping.complete(), [""] = cmp.mapping.abort(), [""] = cmp.mapping.confirm({ select = true }), [""] = cmp.mapping(function(fallback) if cmp.visible() then cmp.select_next_item() elseif luasnip.expand_or_jumpable() then luasnip.expand_or_jump() else fallback() end end, { "i", "s" }), [""] = cmp.mapping(function(fallback) if cmp.visible() then cmp.select_prev_item() elseif luasnip.jumpable(-1) then luasnip.jump(-1) else fallback() end end, { "i", "s" }), }), sources = cmp.config.sources({ { name = "nvim_lsp" }, { name = "luasnip" }, { name = "nvim_lua" }, }, { { name = "buffer" }, }), }) end, }, -- Editing { "stevearc/conform.nvim", opts = { formatters_by_ft = { lua = { "stylua" }, python = { "isort", "black" }, javascript = { "prettierd", "prettier", stop_after_first = true }, java = { "google-java-format" }, }, format_on_save = { timeout_ms = 500, lsp_fallback = true, }, }, }, { "mfussenegger/nvim-lint", event = { "BufReadPre", "BufNewFile" }, config = function() local lint = require("lint") lint.linters_by_ft = { javascript = { "eslint_d" }, typescript = { "eslint_d" }, javascriptreact = { "eslint_d" }, typescriptreact = { "eslint_d" }, python = { "pylint" }, } local lint_augroup = vim.api.nvim_create_augroup("lint", { clear = true }) vim.api.nvim_create_autocmd({ "BufEnter", "BufWritePost", "InsertLeave" }, { group = lint_augroup, callback = function() lint.try_lint() end, }) end, }, { "numtostr/comment.nvim", opts = {}, lazy = false }, { "windwp/nvim-autopairs", event = "InsertEnter", opts = {} }, { "folke/todo-comments.nvim", dependencies = { "nvim-lua/plenary.nvim" }, opts = {} }, { "lukas-reineke/indent-blankline.nvim", main = "ibl", opts = {} }, { "kylechui/nvim-surround", event = "VeryLazy", config = function() require("nvim-surround").setup({}) end, }, { "Cassin01/wf.nvim", version = "*", config = function() require("wf").setup() end, }, -- UI / Theme { "nvim-neo-tree/neo-tree.nvim", branch = "v3.x", dependencies = { "nvim-lua/plenary.nvim", "nvim-tree/nvim-web-devicons", -- not strictly required, but recommended "MunifTanjim/nui.nvim", }, }, { "akinsho/bufferline.nvim", branch = "main", dependencies = "nvim-tree/nvim-web-devicons" }, { "nvim-lualine/lualine.nvim", dependencies = { "nvim-tree/nvim-web-devicons" }, opts = { theme = "codedark" }, }, { "folke/tokyonight.nvim", lazy = false, priority = 1000, opts = { on_highlights = function(hl, c) -- Ensure high contrast for popup menu hl.Pmenu = { bg = "#1f2335", fg = "#c0caf5" } hl.PmenuSel = { bg = "#3d59a1", fg = "#ffffff", bold = true } hl.FloatBorder = { fg = "#3d59a1" } end, }, }, { "hiphish/rainbow-delimiters.nvim" }, -- Telescope { "nvim-telescope/telescope.nvim", dependencies = { "nvim-lua/plenary.nvim" } }, { "lukaspietzschmann/telescope-tabs", dependencies = { "nvim-telescope/telescope.nvim" } }, -- Treesitter { "nvim-treesitter/nvim-treesitter", build = ":TSUpdate", config = function() require("nvim-treesitter.configs").setup({ ensure_installed = { "lua", "groovy", "java", "c", "cpp", "javascript", "python", "yaml", "json", "xml", "html", "ssh_config", "csv", "vim", "vimdoc", "query", "markdown", "markdown_inline", }, sync_install = false, highlight = { enable = true }, indent = { enable = true }, }) end, }, -- Flash { "folke/flash.nvim", event = "VeryLazy", opts = {}, keys = { { "s", mode = { "n", "x", "o" }, function() require("flash").jump() end, desc = "flash", }, { "S", mode = { "n", "x", "o" }, function() require("flash").treesitter() end, desc = "flash treesitter", }, { "r", mode = "o", function() require("flash").remote() end, desc = "remote flash", }, { "R", mode = { "o", "x" }, function() require("flash").treesitter_search() end, desc = "treesitter search", }, { "", mode = { "c" }, function() require("flash").toggle() end, desc = "toggle flash search", }, }, }, -- Markdown { "iamcco/markdown-preview.nvim", cmd = { "Markdownpreviewtoggle", "Markdownpreview", "Markdownpreviewstop" }, build = "cd app && yarn install", init = function() vim.g.mkdp_filetypes = { "markdown" } end, ft = { "markdown" }, }, }) -- Configs vim.g.fubitive_domain_pattern = "bitbucket.ingg.com" -- Correctly setup indent-blankline require("ibl").setup({}) require("bufferline").setup({}) -- Telescope Setup local telescope = require("telescope") local open_with_trouble = require("trouble.sources.telescope").open telescope.setup({ defaults = { mappings = { i = { [""] = open_with_trouble }, n = { [""] = open_with_trouble }, }, }, }) telescope.load_extension("git_worktree") -- Git Worktree local worktree = require("git-worktree") worktree.on_tree_change(function(op, metadata) if op == worktree.operations.switch then print("switched from " .. metadata.prev_path .. " to " .. metadata.path) end end) -- Lualine require("lualine").setup({ sections = { lualine_a = { "mode" }, lualine_b = { { "b:gitsigns_head", icon = "" }, "diff", "diagnostics" }, }, }) -- Colorscheme vim.cmd([[colorscheme tokyonight-night]]) -- Keymaps -- IntelliJ-like Mappings vim.keymap.set("n", "", vim.lsp.buf.code_action, { desc = "Code Action (Alt+Enter)" }) vim.keymap.set("n", "", vim.lsp.buf.rename, { desc = "Rename Symbol (Shift+F6)" }) vim.keymap.set("n", "", function() require("conform").format({ async = true, lsp_fallback = true }) end, { desc = "Reformat Code (Ctrl+Alt+L)" }) -- Navigation & Search vim.keymap.set("n", "", require("telescope.builtin").find_files, { desc = "Go to File (Ctrl+N)" }) vim.keymap.set("n", "", require("telescope.builtin").live_grep, { desc = "Find in Path" }) vim.keymap.set("n", "", require("telescope.builtin").buffers, { desc = "Search Open Files" }) -- LSP Navigation vim.keymap.set("n", "gd", vim.lsp.buf.definition, { desc = "Go to Definition" }) vim.keymap.set("n", "gi", vim.lsp.buf.implementation, { desc = "Go to Implementation" }) vim.keymap.set("n", "gr", require("telescope.builtin").lsp_references, { desc = "Find Usages" }) vim.keymap.set("n", "K", vim.lsp.buf.hover, { desc = "Hover Documentation" }) vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, { desc = "Previous Diagnostic" }) vim.keymap.set("n", "]d", vim.diagnostic.goto_next, { desc = "Next Diagnostic" }) -- Existing Mappings vim.keymap.set("n", "e", ":Neotree toggle", { desc = "Toggle Explorer" }) vim.keymap.set("n", "ft", ":TodoTelescope", { desc = "Find TODOs" }) vim.keymap.set("n", "ff", require("telescope.builtin").find_files, { desc = "List Files" }) vim.keymap.set("n", "fg", require("telescope.builtin").live_grep, { desc = "Search Current Dir" }) vim.keymap.set("n", "fh", require("telescope.builtin").help_tags, { desc = "List Help Tags" }) vim.keymap.set("n", "lg", ":LazyGit", { desc = "LazyGit" }) vim.keymap.set("n", "gws", ":telescope git_worktree git_worktrees", { desc = "List Git Worktrees" }) vim.keymap.set( "n", "gwc", ":telescope git_worktree create_git_worktree", { desc = "Create Git Worktrees " } ) vim.keymap.set("n", "r", ":!%:p", { desc = "Run file" }) -- Trouble (IntelliJ "Problems" View) vim.keymap.set("n", "xx", function() require("trouble").toggle() end, { desc = "Toggle Problems View" }) vim.keymap.set("n", "xw", function() require("trouble").toggle("workspace_diagnostics") end, { desc = "Workspace Problems" }) vim.keymap.set("n", "xd", function() require("trouble").toggle("document_diagnostics") end, { desc = "Document Problems" }) vim.keymap.set("t", "", [[]], { desc = "Escape from terminal" }) -- GitSigns require("gitsigns").setup({ on_attach = function(bufnr) local gs = package.loaded.gitsigns local function map(mode, l, r, opts) opts = opts or {} opts.buffer = bufnr vim.keymap.set(mode, l, r, opts) end -- Navigation map("n", "]c", function() if vim.wo.diff then return "]c" end vim.schedule(function() gs.next_hunk() end) return "" end, { expr = true }) map("n", "[c", function() if vim.wo.diff then return "[c" end vim.schedule(function() gs.prev_hunk() end) return "" end, { expr = true }) -- Actions map("n", "hs", gs.stage_hunk, { desc = "Stage Hunk" }) map("n", "hr", gs.reset_hunk, { desc = "Reset Hunk" }) map("v", "hs", function() gs.stage_hunk({ vim.fn.line("."), vim.fn.line("v") }) end, { desc = "Stage Hunk (v)" }) map("v", "hr", function() gs.reset_hunk({ vim.fn.line("."), vim.fn.line("v") }) end, { desc = "Reset Hunk (v)" }) map("n", "hS", gs.stage_buffer, { desc = "Stage Buffer" }) map("n", "hu", gs.undo_stage_hunk, { desc = "Undo Stage Hunk" }) map("n", "hR", gs.reset_buffer, { desc = "Reset Buffer" }) map("n", "hp", gs.preview_hunk, { desc = "Preview Hunk" }) map("n", "hb", function() gs.blame_line({ full = true }) end, { desc = "Blame Line" }) map("n", "Tb", gs.toggle_current_line_blame, { desc = "Toggle Blame" }) map("n", "hd", gs.diffthis, { desc = "Diff This" }) map("n", "hD", function() gs.diffthis("~") end, { desc = "Diff This ~" }) map("n", "Td", gs.toggle_deleted, { desc = "Toggle Deleted" }) -- Text Object map({ "o", "x" }, "ih", ":Gitsigns select_hunk") end, }) end -- JDTLS Setup local function get_jdtls_config() local mason_registry = require("mason-registry") if not mason_registry.is_installed("jdtls") then vim.notify("JDTLS not installed. Run :MasonInstall jdtls", vim.log.levels.WARN) return nil end local jdtls_path = vim.fn.stdpath("data") .. "/mason/packages/jdtls" -- Find launcher jar local launcher_jars = vim.fn.glob(jdtls_path .. "/plugins/org.eclipse.equinox.launcher_*.jar", true, true) local launcher_jar = launcher_jars[1] if not launcher_jar then vim.notify("JDTLS Launcher JAR not found in " .. jdtls_path, vim.log.levels.ERROR) return nil end local config_dir = jdtls_path .. (vim.fn.has("win32") == 1 and "/config_win" or "/config_linux") local workspace_dir = vim.fn.stdpath("data") .. "/site/java/workspace-root/" .. vim.fn.fnamemodify(vim.fn.getcwd(), ":p:h:t") local java_cmd = "java" if vim.fn.has("win32") == 1 then java_cmd = "C:/Program Files/Eclipse Adoptium/jdk-25.0.1.8-hotspot/bin/java.exe" end local cmd = { java_cmd, "-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-opens", "java.base/java.util=ALL-UNNAMED", "--add-opens", "java.base/java.lang=ALL-UNNAMED", } -- Add Lombok from Mason package if available local lombok_jar = jdtls_path .. "/lombok.jar" if vim.fn.filereadable(lombok_jar) == 1 then table.insert(cmd, "-javaagent:" .. lombok_jar) end -- Finish constructing cmd table.insert(cmd, "-jar") table.insert(cmd, launcher_jar) table.insert(cmd, "-configuration") table.insert(cmd, config_dir) table.insert(cmd, "-data") table.insert(cmd, workspace_dir) local config = { cmd = cmd, root_dir = require("jdtls.setup").find_root({ ".git", "mvnw", "gradlew", "pom.xml", "build.gradle" }), capabilities = require("cmp_nvim_lsp").default_capabilities(), } return config end vim.api.nvim_create_autocmd("FileType", { pattern = "java", callback = function() local config = get_jdtls_config() if config then require("jdtls").start_or_attach(config) end end, })