{pkgs, ...}: let darcula-nvim = pkgs.vimUtils.buildVimPlugin { pname = "darcula"; version = "2024-10-01"; src = pkgs.fetchFromGitHub { owner = "doums"; repo = "darcula"; rev = "faf8dbab27bee0f27e4f1c3ca7e9695af9b1242b"; sha256 = "sha256-Gn+lmlYxSIr91Bg3fth2GAQou2Nd1UjrLkIFbBYlmF8="; }; }; in { fireproof.home-manager.programs.neovim = { enable = true; vimAlias = true; viAlias = true; defaultEditor = true; extraPackages = with pkgs; [ # LSP servers nil # Nix basedpyright # Python nodePackages.typescript-language-server vscode-langservers-extracted # HTML, CSS, JSON, ESLint lua-language-server marksman # Markdown yaml-language-server # Formatters & linters alejandra # Nix formatter stylua # Lua formatter nodePackages.prettier ruff # Python linter/formatter # Tools for plugins ripgrep # for telescope fd # for telescope lazygit # for lazygit.nvim tree-sitter # for treesitter ]; extraLuaConfig = '' -- General settings vim.g.mapleader = " " vim.g.maplocalleader = " " vim.opt.number = true vim.opt.mouse = "a" vim.opt.showmode = false vim.opt.clipboard = "unnamedplus" vim.opt.breakindent = true vim.opt.undofile = true vim.opt.ignorecase = true vim.opt.smartcase = true vim.opt.signcolumn = "yes" vim.opt.updatetime = 250 vim.opt.timeoutlen = 300 vim.opt.splitright = true vim.opt.splitbelow = true vim.opt.list = true vim.opt.listchars = { tab = "» ", trail = "·", nbsp = "␣" } vim.opt.inccommand = "split" vim.opt.cursorline = true vim.opt.scrolloff = 10 vim.opt.hlsearch = true vim.opt.termguicolors = true vim.opt.tabstop = 2 vim.opt.shiftwidth = 2 vim.opt.expandtab = true -- Clear search highlight on pressing vim.keymap.set("n", "", "nohlsearch") -- Diagnostic keymaps vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, { desc = "Go to previous diagnostic" }) vim.keymap.set("n", "]d", vim.diagnostic.goto_next, { desc = "Go to next diagnostic" }) vim.keymap.set("n", "e", vim.diagnostic.open_float, { desc = "Show diagnostic error" }) vim.keymap.set("n", "q", vim.diagnostic.setloclist, { desc = "Open diagnostic quickfix" }) -- Window navigation vim.keymap.set("n", "", "", { desc = "Move to left window" }) vim.keymap.set("n", "", "", { desc = "Move to right window" }) vim.keymap.set("n", "", "", { desc = "Move to lower window" }) vim.keymap.set("n", "", "", { desc = "Move to upper window" }) -- Better indenting vim.keymap.set("v", "<", "", ">gv") ''; plugins = with pkgs.vimPlugins; [ # Colorscheme (JetBrains/Darcula theme) { plugin = darcula-nvim; type = "lua"; config = '' vim.cmd.colorscheme("darcula") ''; } # File explorer { plugin = neo-tree-nvim; type = "lua"; config = '' require("neo-tree").setup({ filesystem = { follow_current_file = { enabled = true }, hijack_netrw_behavior = "open_current", }, }) vim.keymap.set("n", "e", "Neotree toggle", { desc = "Toggle file explorer" }) ''; } nvim-web-devicons plenary-nvim # Fuzzy finder { plugin = telescope-nvim; type = "lua"; config = '' local telescope = require("telescope") local builtin = require("telescope.builtin") telescope.setup({ defaults = { file_ignore_patterns = { "node_modules", ".git/", "__pycache__" }, }, }) vim.keymap.set("n", "ff", builtin.find_files, { desc = "Find files" }) vim.keymap.set("n", "fg", builtin.live_grep, { desc = "Live grep" }) vim.keymap.set("n", "fb", builtin.buffers, { desc = "Find buffers" }) vim.keymap.set("n", "fh", builtin.help_tags, { desc = "Help tags" }) vim.keymap.set("n", "fr", builtin.oldfiles, { desc = "Recent files" }) vim.keymap.set("n", "fd", builtin.diagnostics, { desc = "Diagnostics" }) vim.keymap.set("n", "fs", builtin.lsp_document_symbols, { desc = "Document symbols" }) ''; } telescope-fzf-native-nvim # Treesitter for syntax highlighting { plugin = nvim-treesitter.withAllGrammars; type = "lua"; config = '' require("nvim-treesitter.configs").setup({ highlight = { enable = true }, indent = { enable = true }, incremental_selection = { enable = true, keymaps = { init_selection = "", node_incremental = "", scope_incremental = false, node_decremental = "", }, }, }) ''; } # LSP { plugin = nvim-lspconfig; type = "lua"; config = '' -- LSP keymaps on attach vim.api.nvim_create_autocmd("LspAttach", { group = vim.api.nvim_create_augroup("lsp-attach", { clear = true }), callback = function(event) local map = function(keys, func, desc) vim.keymap.set("n", keys, func, { buffer = event.buf, desc = "LSP: " .. desc }) end map("gd", vim.lsp.buf.definition, "Go to definition") map("gr", vim.lsp.buf.references, "Go to references") map("gI", vim.lsp.buf.implementation, "Go to implementation") map("D", vim.lsp.buf.type_definition, "Type definition") map("rn", vim.lsp.buf.rename, "Rename") map("ca", vim.lsp.buf.code_action, "Code action") map("K", vim.lsp.buf.hover, "Hover documentation") map("gD", vim.lsp.buf.declaration, "Go to declaration") end, }) -- Configure LSP servers using vim.lsp.config (Neovim 0.11+) vim.lsp.config("nil_ls", {}) vim.lsp.config("basedpyright", {}) vim.lsp.config("ts_ls", {}) vim.lsp.config("lua_ls", { settings = { Lua = { runtime = { version = "LuaJIT" }, diagnostics = { globals = { "vim" } }, }, }, }) vim.lsp.config("jsonls", {}) vim.lsp.config("yamlls", {}) vim.lsp.config("marksman", {}) -- Enable the configured LSP servers vim.lsp.enable({ "nil_ls", "basedpyright", "ts_ls", "lua_ls", "jsonls", "yamlls", "marksman" }) ''; } # Autocompletion { plugin = nvim-cmp; type = "lua"; config = '' local cmp = require("cmp") local luasnip = require("luasnip") luasnip.config.setup({}) cmp.setup({ snippet = { expand = function(args) luasnip.lsp_expand(args.body) end, }, completion = { completeopt = "menu,menuone,noinsert" }, mapping = cmp.mapping.preset.insert({ [""] = cmp.mapping.select_next_item(), [""] = cmp.mapping.select_prev_item(), [""] = cmp.mapping.scroll_docs(-4), [""] = cmp.mapping.scroll_docs(4), [""] = cmp.mapping.confirm({ select = true }), [""] = cmp.mapping.complete({}), [""] = cmp.mapping(function(fallback) if cmp.visible() then cmp.select_next_item() elseif luasnip.expand_or_locally_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.locally_jumpable(-1) then luasnip.jump(-1) else fallback() end end, { "i", "s" }), }), sources = { { name = "nvim_lsp" }, { name = "luasnip" }, { name = "buffer" }, { name = "path" }, }, }) ''; } cmp-nvim-lsp cmp-buffer cmp-path luasnip cmp_luasnip friendly-snippets # Formatting { plugin = conform-nvim; type = "lua"; config = '' require("conform").setup({ formatters_by_ft = { lua = { "stylua" }, python = { "ruff_format" }, javascript = { "prettier" }, typescript = { "prettier" }, javascriptreact = { "prettier" }, typescriptreact = { "prettier" }, json = { "prettier" }, yaml = { "prettier" }, markdown = { "prettier" }, html = { "prettier" }, css = { "prettier" }, nix = { "alejandra" }, }, format_on_save = { timeout_ms = 500, lsp_fallback = true, }, }) vim.keymap.set({ "n", "v" }, "cf", function() require("conform").format({ async = true, lsp_fallback = true }) end, { desc = "Format buffer" }) ''; } # Git integration { plugin = gitsigns-nvim; type = "lua"; config = '' require("gitsigns").setup({ signs = { add = { text = "▎" }, change = { text = "▎" }, delete = { text = "" }, topdelete = { text = "" }, changedelete = { text = "▎" }, }, 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 map("n", "]c", gs.next_hunk, { desc = "Next git hunk" }) map("n", "[c", gs.prev_hunk, { desc = "Previous git hunk" }) map("n", "hs", gs.stage_hunk, { desc = "Stage hunk" }) map("n", "hr", gs.reset_hunk, { desc = "Reset hunk" }) map("n", "hb", gs.blame_line, { desc = "Blame line" }) map("n", "hp", gs.preview_hunk, { desc = "Preview hunk" }) end, }) ''; } { plugin = lazygit-nvim; type = "lua"; config = '' vim.keymap.set("n", "gg", "LazyGit", { desc = "Open LazyGit" }) ''; } # UI improvements { plugin = lualine-nvim; type = "lua"; config = '' require("lualine").setup({ options = { theme = "auto", component_separators = { left = "", right = "" }, section_separators = { left = "", right = "" }, }, }) ''; } { plugin = indent-blankline-nvim; type = "lua"; config = '' require("ibl").setup({ indent = { char = "│" }, scope = { enabled = true }, }) ''; } { plugin = which-key-nvim; type = "lua"; config = '' require("which-key").setup({}) require("which-key").add({ { "f", group = "Find" }, { "c", group = "Code" }, { "h", group = "Git Hunk" }, { "g", group = "Git" }, }) ''; } # Autopairs { plugin = nvim-autopairs; type = "lua"; config = '' require("nvim-autopairs").setup({}) ''; } # Comments { plugin = comment-nvim; type = "lua"; config = '' require("Comment").setup({}) ''; } # Surround { plugin = nvim-surround; type = "lua"; config = '' require("nvim-surround").setup({}) ''; } ]; }; }