diff --git a/flake.lock b/flake.lock index 9be72f7..f34ea20 100644 --- a/flake.lock +++ b/flake.lock @@ -59,27 +59,6 @@ "type": "github" } }, - "flake-parts": { - "inputs": { - "nixpkgs-lib": [ - "nixvim", - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1778716662, - "narHash": "sha256-m1Yf0wZ8j1OHjTc2UwHwyQRSnNeSgLJOd7q5Y45hzi4=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "f7c1a2d347e4c52d5fb8d10cb4d94b5884e546fb", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "flake-parts", - "type": "github" - } - }, "flake-utils": { "inputs": { "systems": "systems" @@ -118,7 +97,7 @@ }, "flake-utils_3": { "inputs": { - "systems": "systems_4" + "systems": "systems_3" }, "locked": { "lastModified": 1681202837, @@ -211,6 +190,26 @@ "type": "github" } }, + "nix-wrapper-modules": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1782135443, + "narHash": "sha256-vAmbArdCyjqpVW+37aCy/PMBOLIqukUXLQuEKLwUhA4=", + "owner": "BirdeeHub", + "repo": "nix-wrapper-modules", + "rev": "6e7f66fa2cdf4d63162580b438f7fcf87c28a46f", + "type": "github" + }, + "original": { + "owner": "BirdeeHub", + "repo": "nix-wrapper-modules", + "type": "github" + } + }, "nixpkgs": { "locked": { "lastModified": 1767892417, @@ -240,28 +239,6 @@ "type": "github" } }, - "nixvim": { - "inputs": { - "flake-parts": "flake-parts", - "nixpkgs": [ - "nixpkgs" - ], - "systems": "systems_3" - }, - "locked": { - "lastModified": 1782919563, - "narHash": "sha256-vVYo8fbgTgXBU47dLmnUcfetOI/MLui+wXU44x3ZeqM=", - "owner": "nix-community", - "repo": "nixvim", - "rev": "702008d2b3dd1d032a953e3bdd2532531aac0639", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "nixvim", - "type": "github" - } - }, "root": { "inputs": { "antigravity-nix": "antigravity-nix", @@ -270,8 +247,8 @@ "home-manager": "home-manager", "nix-darwin": "nix-darwin", "nix-homebrew": "nix-homebrew", + "nix-wrapper-modules": "nix-wrapper-modules", "nixpkgs": "nixpkgs_2", - "nixvim": "nixvim", "sops-nix": "sops-nix", "vantage": "vantage", "vscode-server": "vscode-server" @@ -328,22 +305,6 @@ } }, "systems_3": { - "locked": { - "lastModified": 1774449309, - "narHash": "sha256-brhZ8DmuGtzkCYHJg4HEd602amKm89Y9ytsFZ5uWD1w=", - "owner": "nix-systems", - "repo": "default", - "rev": "c29398b59d2048c4ab79345812849c9bd15e9150", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "ref": "future-26.11", - "repo": "default", - "type": "github" - } - }, - "systems_4": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", diff --git a/flake.nix b/flake.nix index ea026d7..6635bb9 100644 --- a/flake.nix +++ b/flake.nix @@ -15,8 +15,8 @@ nix-homebrew = { url = "github:zhaofengli-wip/nix-homebrew"; }; - nixvim = { - url = "github:nix-community/nixvim"; + nix-wrapper-modules = { + url = "github:BirdeeHub/nix-wrapper-modules"; inputs.nixpkgs.follows = "nixpkgs"; }; hardware = { diff --git a/lib/flakeHelpers.nix b/lib/flakeHelpers.nix index 40d3f83..75ea27d 100644 --- a/lib/flakeHelpers.nix +++ b/lib/flakeHelpers.nix @@ -3,7 +3,7 @@ { inputs, lib, self, overlays }: let - inherit (inputs) nixpkgs nix-darwin home-manager nixvim vscode-server hardware charon-key sops-nix antigravity-nix; + inherit (inputs) nixpkgs nix-darwin home-manager vscode-server hardware charon-key sops-nix antigravity-nix; # Helper to wrap a module file and filter out 'meta' attribute # NixOS modules don't allow arbitrary top-level attributes @@ -96,7 +96,6 @@ in modules = [ host-config ] ++ [ home-manager.darwinModules.home-manager - nixvim.nixDarwinModules.nixvim charon-key.darwinModules.default # antigravity-nix exposes only packages/overlays (no darwinModules); # google-antigravity* are injected via overlays/additions.nix @@ -128,7 +127,6 @@ in ++ [ # Core NixOS modules from inputs home-manager.nixosModules.home-manager - nixvim.nixosModules.nixvim vscode-server.nixosModules.default charon-key.nixosModules.default sops-nix.nixosModules.sops diff --git a/modules/home/editors/neovim/dotfiles/colorschema.nix b/modules/home/editors/neovim/dotfiles/colorschema.nix deleted file mode 100644 index 385bb80..0000000 --- a/modules/home/editors/neovim/dotfiles/colorschema.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ ... }: { - config = { - programs.nixvim = { - colorschemes = { - catppuccin = { - enable = true; - }; - }; - }; - }; -} diff --git a/modules/home/editors/neovim/dotfiles/general.nix b/modules/home/editors/neovim/dotfiles/general.nix deleted file mode 100644 index 2c4bf15..0000000 --- a/modules/home/editors/neovim/dotfiles/general.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ ... }: { - config.programs.nixvim = { - opts = { - shiftwidth = 2; - - number = true; - relativenumber = true; - timeoutlen = 300; - }; - }; -} diff --git a/modules/home/editors/neovim/dotfiles/keymaps.nix b/modules/home/editors/neovim/dotfiles/keymaps.nix deleted file mode 100644 index 349d426..0000000 --- a/modules/home/editors/neovim/dotfiles/keymaps.nix +++ /dev/null @@ -1,5 +0,0 @@ -{ ... }: { - config.programs.nixvim = { - globals.mapleader = " "; - }; -} diff --git a/modules/home/editors/neovim/dotfiles/nvim/init.lua b/modules/home/editors/neovim/dotfiles/nvim/init.lua new file mode 100644 index 0000000..c70d08a --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/init.lua @@ -0,0 +1,35 @@ +-- ╭──────────────────────────────────────────────────────────╮ +-- │ LazyVim-like Neovim Configuration │ +-- │ Plugins are pre-installed by Nix (nix-wrapper-modules) │ +-- │ Edit these Lua files → restart nvim — no rebuild! │ +-- ╰──────────────────────────────────────────────────────────╯ + +-- Leader key must be set before any plugin loads +vim.g.mapleader = " " +vim.g.maplocalleader = "\\" + +-- Enable byte-compiled loader for faster startup +vim.loader.enable() + +-- Load core configuration +require("config.options") +require("config.keymaps") +require("config.autocmds") + +-- Auto-load all plugin configs from lua/plugins/**/*.lua +local function load_plugin_configs(base_dir) + local config_path = vim.fn.stdpath("config") .. "/lua/" .. base_dir + if vim.fn.isdirectory(config_path) == 0 then + return + end + + for _, file in ipairs(vim.fn.glob(config_path .. "/**/*.lua", false, true)) do + local module = file:match("lua/(.+)%.lua$"):gsub("/", ".") + local ok, err = pcall(require, module) + if not ok then + vim.notify("Error loading " .. module .. ":\n" .. err, vim.log.levels.ERROR) + end + end +end + +load_plugin_configs("plugins") diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/config/autocmds.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/config/autocmds.lua new file mode 100644 index 0000000..e632389 --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/config/autocmds.lua @@ -0,0 +1,74 @@ +-- LazyVim-style autocommands +local autocmd = vim.api.nvim_create_autocmd +local augroup = vim.api.nvim_create_augroup + +-- Highlight on yank +autocmd("TextYankPost", { + group = augroup("highlight_yank", { clear = true }), + callback = function() + vim.highlight.on_yank() + end, +}) + +-- Resize splits on window resize +autocmd("VimResized", { + group = augroup("resize_splits", { clear = true }), + callback = function() + local current_tab = vim.fn.tabpagenr() + vim.cmd("tabdo wincmd =") + vim.cmd("tabnext " .. current_tab) + end, +}) + +-- Restore cursor position when opening a buffer +autocmd("BufReadPost", { + group = augroup("last_loc", { clear = true }), + callback = function(event) + local exclude = { "gitcommit" } + local buf = event.buf + if vim.tbl_contains(exclude, vim.bo[buf].filetype) or vim.b[buf].last_loc then + return + end + vim.b[buf].last_loc = true + local mark = vim.api.nvim_buf_get_mark(buf, '"') + local lcount = vim.api.nvim_buf_line_count(buf) + if mark[1] > 0 and mark[1] <= lcount then + pcall(vim.api.nvim_win_set_cursor, 0, mark) + end + end, +}) + +-- Close some filetypes with +autocmd("FileType", { + group = augroup("close_with_q", { clear = true }), + pattern = { + "help", "lspinfo", "notify", "qf", "query", + "startuptime", "checkhealth", + }, + callback = function(event) + vim.bo[event.buf].buflisted = false + vim.keymap.set("n", "q", "close", { buffer = event.buf, silent = true }) + end, +}) + +-- Auto create parent dirs when saving a new file +autocmd("BufWritePre", { + group = augroup("auto_create_dir", { clear = true }), + callback = function(event) + if event.match:match("^%w%w+:[\\/][\\/]") then + return + end + local file = vim.uv.fs_realpath(event.match) or event.match + vim.fn.mkdir(vim.fn.fnamemodify(file, ":p:h"), "p") + end, +}) + +-- Wrap and spell in text filetypes +autocmd("FileType", { + group = augroup("wrap_spell", { clear = true }), + pattern = { "text", "plaintex", "typst", "gitcommit", "markdown" }, + callback = function() + vim.opt_local.wrap = true + vim.opt_local.spell = true + end, +}) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/config/keymaps.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/config/keymaps.lua new file mode 100644 index 0000000..8de1978 --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/config/keymaps.lua @@ -0,0 +1,64 @@ +-- LazyVim-style keymaps +local map = vim.keymap.set + +-- ── Window navigation ── +map("n", "", "h", { desc = "Go to left window" }) +map("n", "", "j", { desc = "Go to lower window" }) +map("n", "", "k", { desc = "Go to upper window" }) +map("n", "", "l", { desc = "Go to right window" }) + +-- ── Resize windows ── +map("n", "", "resize +2", { desc = "Increase window height" }) +map("n", "", "resize -2", { desc = "Decrease window height" }) +map("n", "", "vertical resize -2", { desc = "Decrease window width" }) +map("n", "", "vertical resize +2", { desc = "Increase window width" }) + +-- ── Buffer navigation ── +map("n", "", "bprevious", { desc = "Prev buffer" }) +map("n", "", "bnext", { desc = "Next buffer" }) +map("n", "bd", function() Snacks.bufdelete() end, { desc = "Close buffer" }) +map("n", "bD", "bdelete!", { desc = "Close buffer (force)" }) + +-- ── Move lines ── +map("n", "", "move .+1==", { desc = "Move line down" }) +map("n", "", "move .-2==", { desc = "Move line up" }) +map("v", "", ":move '>+1gv=gv", { desc = "Move selection down" }) +map("v", "", ":move '<-2gv=gv", { desc = "Move selection up" }) +map("i", "", "move .+1==gi", { desc = "Move line down" }) +map("i", "", "move .-2==gi", { desc = "Move line up" }) + +-- ── Save / Quit ── +map("n", "w", "w", { desc = "Save" }) +map("n", "q", "q", { desc = "Quit" }) +map("n", "Q", "qa", { desc = "Quit all" }) + +-- ── Clear search highlight ── +map({ "i", "n" }, "", "noh", { desc = "Escape and clear hlsearch" }) +map("n", "ur", "nohlsearchdiffupdatenormal! ", { desc = "Redraw / clear hlsearch" }) + +-- ── Better indenting (stay in visual mode) ── +map("v", "<", "", ">gv") + +-- ── New file ── +map("n", "fn", "enew", { desc = "New file" }) + +-- ── Diagnostics ── +map("n", "]d", vim.diagnostic.goto_next, { desc = "Next diagnostic" }) +map("n", "[d", vim.diagnostic.goto_prev, { desc = "Prev diagnostic" }) +map("n", "cd", vim.diagnostic.open_float, { desc = "Line diagnostics" }) + +-- ── Terminal ── +map("t", "", "", { desc = "Enter Normal Mode" }) + +-- ── Misc ── +map("n", "R", function() + -- Clear Lua module cache for our config + for name, _ in pairs(package.loaded) do + if name:match("^config%.") or name:match("^plugins%.") then + package.loaded[name] = nil + end + end + dofile(vim.fn.stdpath("config") .. "/init.lua") + vim.notify("Config reloaded!", vim.log.levels.INFO) +end, { desc = "Reload config" }) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/config/options.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/config/options.lua new file mode 100644 index 0000000..46dd808 --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/config/options.lua @@ -0,0 +1,64 @@ +-- LazyVim-equivalent vim options +local opt = vim.opt + +-- Line numbers +opt.number = true +opt.relativenumber = true + +-- Tabs & indentation +opt.expandtab = true +opt.shiftwidth = 2 +opt.tabstop = 2 +opt.smartindent = true +opt.shiftround = true + +-- Search +opt.ignorecase = true +opt.smartcase = true +opt.hlsearch = true +opt.incsearch = true + +-- Appearance +opt.termguicolors = true +opt.signcolumn = "yes" +opt.cursorline = true +opt.scrolloff = 4 +opt.sidescrolloff = 8 +opt.wrap = false +opt.showmode = false -- statusline handles this + +-- Windows +opt.splitright = true +opt.splitbelow = true +opt.splitkeep = "screen" + +-- Clipboard +opt.clipboard = "unnamedplus" + +-- Undo +opt.undofile = true +opt.undolevels = 10000 + +-- Behavior +opt.timeoutlen = 300 +opt.updatetime = 200 +opt.completeopt = "menu,menuone,noselect" +opt.wildmode = "longest:full,full" +opt.mouse = "a" +opt.confirm = true -- confirm to save changes before closing buffer + +-- Fill chars +opt.fillchars = { + diff = "╱", + eob = " ", +} + +-- Grep (use ripgrep) +opt.grepformat = "%f:%l:%c:%m" +opt.grepprg = "rg --vimgrep" + +-- Sessions +opt.sessionoptions = { "buffers", "curdir", "tabpages", "winsize", "help", "globals", "skiprtp", "folds" } + +-- Spelling +opt.spelllang = { "en" } diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ai/init.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ai/init.lua new file mode 100644 index 0000000..d9d0c8c --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ai/init.lua @@ -0,0 +1,3 @@ +-- AI plugin configurations +-- Add AI integrations here as needed +-- Example: copilot, codeium, avante, etc. diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/coding/completion.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/coding/completion.lua new file mode 100644 index 0000000..d0dc821 --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/coding/completion.lua @@ -0,0 +1,28 @@ +-- Autocompletion engine (blink.cmp) +require("blink.cmp").setup({ + keymap = { preset = "enter" }, + appearance = { + use_nvim_cmp_as_default = false, + nerd_font_variant = "mono", + }, + sources = { + default = { "lsp", "path", "snippets", "buffer" }, + }, + completion = { + accept = { + auto_brackets = { enabled = true }, + }, + menu = { + draw = { + treesitter = { "lsp" }, + }, + }, + documentation = { + auto_show = true, + auto_show_delay_ms = 200, + }, + ghost_text = { + enabled = true, + }, + }, +}) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/coding/mini.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/coding/mini.lua new file mode 100644 index 0000000..a22be0d --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/coding/mini.lua @@ -0,0 +1,5 @@ +-- mini.nvim modules +require("mini.pairs").setup({}) -- auto-close brackets +require("mini.surround").setup({}) -- surround text objects (sa, sd, sr) +require("mini.ai").setup({}) -- enhanced text objects +require("mini.comment").setup({}) -- toggle comments (gc) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/coding/treesitter.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/coding/treesitter.lua new file mode 100644 index 0000000..023fc94 --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/coding/treesitter.lua @@ -0,0 +1,35 @@ +-- Treesitter — syntax highlighting, text objects, indent +-- Grammars are pre-installed by Nix (withAllGrammars in plugins.nix) +-- No need for nvim-treesitter.configs — use built-in Neovim treesitter APIs + +-- Enable treesitter highlighting for all supported filetypes +vim.api.nvim_create_autocmd("FileType", { + group = vim.api.nvim_create_augroup("treesitter_start", { clear = true }), + callback = function() + pcall(vim.treesitter.start) + end, +}) + +-- Enable treesitter-based indentation +vim.opt.foldmethod = "expr" +vim.opt.foldexpr = "v:lua.vim.treesitter.foldexpr()" +vim.opt.foldenable = false -- don't fold by default +vim.opt.foldlevel = 99 + +-- Incremental selection via nvim-treesitter (if available) +local ok, configs = pcall(require, "nvim-treesitter.configs") +if ok then + configs.setup({ + highlight = { enable = true }, + indent = { enable = true }, + incremental_selection = { + enable = true, + keymaps = { + init_selection = "", + node_incremental = "", + scope_incremental = false, + node_decremental = "", + }, + }, + }) +end diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/flash.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/flash.lua new file mode 100644 index 0000000..db1dc57 --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/flash.lua @@ -0,0 +1,7 @@ +-- Motion / jump plugin +require("flash").setup({}) + +vim.keymap.set({ "n", "x", "o" }, "s", function() require("flash").jump() end, { desc = "Flash" }) +vim.keymap.set({ "n", "x", "o" }, "S", function() require("flash").treesitter() end, { desc = "Flash Treesitter" }) +vim.keymap.set("o", "r", function() require("flash").remote() end, { desc = "Remote Flash" }) +vim.keymap.set({ "o", "x" }, "R", function() require("flash").treesitter_search() end, { desc = "Treesitter Search" }) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/gitsigns.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/gitsigns.lua new file mode 100644 index 0000000..76ef2de --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/gitsigns.lua @@ -0,0 +1,41 @@ +-- Git change indicators in sign column +require("gitsigns").setup({ + signs = { + add = { text = "▎" }, + change = { text = "▎" }, + delete = { text = "" }, + topdelete = { text = "" }, + changedelete = { text = "▎" }, + untracked = { text = "▎" }, + }, + signs_staged = { + add = { text = "▎" }, + change = { text = "▎" }, + delete = { text = "" }, + topdelete = { text = "" }, + changedelete = { text = "▎" }, + }, + on_attach = function(buffer) + local gs = package.loaded.gitsigns + local function map(mode, l, r, desc) + vim.keymap.set(mode, l, r, { buffer = buffer, desc = desc }) + end + map("n", "]h", function() gs.nav_hunk("next") end, "Next hunk") + map("n", "[h", function() gs.nav_hunk("prev") end, "Prev hunk") + map({ "n", "v" }, "ghs", ":Gitsigns stage_hunk", "Stage hunk") + map({ "n", "v" }, "ghr", ":Gitsigns reset_hunk", "Reset hunk") + map("n", "ghS", gs.stage_buffer, "Stage buffer") + map("n", "ghu", gs.undo_stage_hunk, "Undo stage hunk") + map("n", "ghR", gs.reset_buffer, "Reset buffer") + map("n", "ghp", gs.preview_hunk_inline, "Preview hunk inline") + map("n", "ghb", function() gs.blame_line({ full = true }) end, "Blame line") + map("n", "ghB", gs.toggle_current_line_blame, "Toggle inline blame") + map("n", "ghd", gs.diffthis, "Diff this") + end, + current_line_blame = true, + current_line_blame_opts = { + virt_text = true, + virt_text_pos = "eol", + delay = 300, + }, +}) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/neo-tree.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/neo-tree.lua new file mode 100644 index 0000000..8f3ab6e --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/neo-tree.lua @@ -0,0 +1,44 @@ +-- File explorer sidebar +require("neo-tree").setup({ + sources = { "filesystem", "buffers", "git_status" }, + open_files_do_not_replace_types = { "terminal", "Trouble", "trouble", "qf", "Outline" }, + filesystem = { + bind_to_cwd = false, + follow_current_file = { enabled = true }, + use_libuv_file_watcher = true, + filtered_items = { + visible = true, + hide_dotfiles = false, + hide_gitignored = false, + }, + }, + window = { + width = 30, + mappings = { + [""] = "none", + ["Y"] = function(state) + local node = state.tree:get_node() + local path = node:get_id() + vim.fn.setreg("+", path, "c") + vim.notify("Copied: " .. path) + end, + }, + }, + default_component_configs = { + indent = { + with_expanders = true, + expander_collapsed = "", + expander_expanded = "", + expander_highlight = "NeoTreeExpander", + }, + git_status = { + symbols = { + unstaged = "󰄱", + staged = "󰱒", + }, + }, + }, +}) + +vim.keymap.set("n", "e", "Neotree toggle", { desc = "Explorer (toggle)" }) +vim.keymap.set("n", "fe", "Neotree toggle", { desc = "Explorer (toggle)" }) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/sessions.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/sessions.lua new file mode 100644 index 0000000..2fb0c57 --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/sessions.lua @@ -0,0 +1,89 @@ +-- Session management — remember open buffers per project directory +-- Sessions are stored in ~/.local/share/nvim/sessions/ + +local session_dir = vim.fn.stdpath("data") .. "/sessions/" +vim.fn.mkdir(session_dir, "p") + +-- Convert cwd to a safe filename +local function session_file() + local cwd = vim.fn.getcwd() + local name = cwd:gsub("/", "%%") + return session_dir .. name .. ".vim" +end + +-- Save session +local function save_session() + vim.cmd("mksession! " .. vim.fn.fnameescape(session_file())) +end + +vim.keymap.set("n", "qs", function() + save_session() + vim.notify("Session saved for " .. vim.fn.getcwd()) +end, { desc = "Save session" }) + +-- Restore session +vim.keymap.set("n", "qr", function() + local f = session_file() + if vim.fn.filereadable(f) == 1 then + -- Close dashboard if open + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + if vim.bo[buf].filetype == "snacks_dashboard" then + vim.api.nvim_buf_delete(buf, { force = true }) + end + end + vim.cmd("source " .. vim.fn.fnameescape(f)) + vim.notify("Session restored for " .. vim.fn.getcwd()) + else + vim.notify("No session found for " .. vim.fn.getcwd(), vim.log.levels.WARN) + end +end, { desc = "Restore session" }) + +-- Auto-save session on exit (always save if there are real buffers) +vim.api.nvim_create_autocmd("VimLeavePre", { + group = vim.api.nvim_create_augroup("auto_save_session", { clear = true }), + callback = function() + local bufs = vim.tbl_filter(function(b) + return vim.bo[b].buflisted + and vim.bo[b].buftype == "" + and vim.bo[b].filetype ~= "snacks_dashboard" + end, vim.api.nvim_list_bufs()) + if #bufs > 0 then + -- Close Neo-tree before saving so it doesn't persist its window size + pcall(vim.cmd, "Neotree close") + save_session() + end + end, +}) + +-- Auto-restore session on startup +vim.api.nvim_create_autocmd("VimEnter", { + group = vim.api.nvim_create_augroup("auto_restore_session", { clear = true }), + callback = function() + -- Only when opening nvim with no file args or a directory + if vim.fn.argc() > 0 and vim.fn.isdirectory(vim.fn.argv(0)) == 0 then + return + end + local f = session_file() + if vim.fn.filereadable(f) ~= 1 then + return + end + -- Defer to run after dashboard and other plugins finish + vim.schedule(function() + -- Close dashboard and directory buffers before restoring + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + local ft = vim.bo[buf].filetype + if ft == "snacks_dashboard" or ft == "netrw" or ft == "neo-tree" then + vim.api.nvim_buf_delete(buf, { force = true }) + end + end + -- Also close any buffer that's just showing a directory + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + local name = vim.api.nvim_buf_get_name(buf) + if vim.fn.isdirectory(name) == 1 then + vim.api.nvim_buf_delete(buf, { force = true }) + end + end + vim.cmd("silent! source " .. vim.fn.fnameescape(f)) + end) + end, +}) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/telescope.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/telescope.lua new file mode 100644 index 0000000..2613f34 --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/telescope.lua @@ -0,0 +1,37 @@ +-- Fuzzy finder +local telescope = require("telescope") +local actions = require("telescope.actions") + +telescope.setup({ + defaults = { + prompt_prefix = " ", + selection_caret = " ", + mappings = { + i = { + [""] = actions.move_selection_next, + [""] = actions.move_selection_previous, + [""] = actions.cycle_history_next, + [""] = actions.cycle_history_prev, + [""] = actions.close, + }, + }, + }, +}) + +-- Load fzf native extension +pcall(telescope.load_extension, "fzf") + +-- Keymaps +local builtin = require("telescope.builtin") +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 = "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", "fc", builtin.git_commits, { desc = "Git commits" }) +vim.keymap.set("n", "fs", builtin.git_status, { desc = "Git status" }) +vim.keymap.set("n", "/", builtin.live_grep, { desc = "Grep (root)" }) +vim.keymap.set("n", "", builtin.find_files, { desc = "Find files" }) +vim.keymap.set("n", "sd", builtin.diagnostics, { desc = "Diagnostics" }) +vim.keymap.set("n", "sw", builtin.grep_string, { desc = "Word under cursor" }) +vim.keymap.set("n", "sk", builtin.keymaps, { desc = "Keymaps" }) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/todo-comments.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/todo-comments.lua new file mode 100644 index 0000000..17a6db6 --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/todo-comments.lua @@ -0,0 +1,7 @@ +-- Highlight TODO/FIXME/HACK/NOTE comments +require("todo-comments").setup({}) + +vim.keymap.set("n", "]t", function() require("todo-comments").jump_next() end, { desc = "Next TODO" }) +vim.keymap.set("n", "[t", function() require("todo-comments").jump_prev() end, { desc = "Prev TODO" }) +vim.keymap.set("n", "xt", "Trouble todo toggle", { desc = "TODOs (Trouble)" }) +vim.keymap.set("n", "st", "TodoTelescope", { desc = "TODOs (Telescope)" }) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/trouble.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/trouble.lua new file mode 100644 index 0000000..219bf1f --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/editor/trouble.lua @@ -0,0 +1,10 @@ +-- Diagnostics / quickfix list +require("trouble").setup({ + use_diagnostic_signs = true, +}) + +vim.keymap.set("n", "xx", "Trouble diagnostics toggle", { desc = "Diagnostics (Trouble)" }) +vim.keymap.set("n", "xX", "Trouble diagnostics toggle filter.buf=0", { desc = "Buffer diagnostics" }) +vim.keymap.set("n", "cs", "Trouble symbols toggle focus=false", { desc = "Symbols (Trouble)" }) +vim.keymap.set("n", "xL", "Trouble loclist toggle", { desc = "Location list" }) +vim.keymap.set("n", "xQ", "Trouble qflist toggle", { desc = "Quickfix list" }) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/formatting/conform.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/formatting/conform.lua new file mode 100644 index 0000000..b43161e --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/formatting/conform.lua @@ -0,0 +1,32 @@ +-- Formatting (conform.nvim) +-- Formatters are installed via Nix (runtimePkgs in plugins.nix) +require("conform").setup({ + formatters_by_ft = { + lua = { "stylua" }, + nix = { "nixpkgs_fmt" }, + python = { "black" }, + go = { "gofumpt" }, + javascript = { "prettier" }, + typescript = { "prettier" }, + javascriptreact = { "prettier" }, + typescriptreact = { "prettier" }, + html = { "prettier" }, + css = { "prettier" }, + json = { "prettier" }, + yaml = { "prettier" }, + markdown = { "prettier" }, + c = { "clang_format" }, + cpp = { "clang_format" }, + rust = { "rustfmt" }, + sh = { "shfmt" }, + bash = { "shfmt" }, + }, + format_on_save = { + timeout_ms = 3000, + lsp_fallback = true, + }, +}) + +vim.keymap.set({ "n", "v" }, "cf", function() + require("conform").format({ async = true, lsp_fallback = true }) +end, { desc = "Format" }) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/lang/init.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/lang/init.lua new file mode 100644 index 0000000..25947a4 --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/lang/init.lua @@ -0,0 +1,3 @@ +-- Language-specific configurations +-- Add language packs here as needed +-- Example: require("plugins.lang.python") diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/linting/lint.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/linting/lint.lua new file mode 100644 index 0000000..d2cb980 --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/linting/lint.lua @@ -0,0 +1,14 @@ +-- Linting (nvim-lint) +-- Linters are installed via Nix (runtimePkgs in plugins.nix) +require("lint").linters_by_ft = { + sh = { "shellcheck" }, + bash = { "shellcheck" }, +} + +-- Auto-lint on save and text change +vim.api.nvim_create_autocmd({ "BufWritePost", "BufReadPost", "InsertLeave" }, { + group = vim.api.nvim_create_augroup("nvim-lint", { clear = true }), + callback = function() + require("lint").try_lint() + end, +}) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/lsp/lspconfig.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/lsp/lspconfig.lua new file mode 100644 index 0000000..2b18b89 --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/lsp/lspconfig.lua @@ -0,0 +1,131 @@ +-- LSP configuration (Neovim 0.11+ native API) +-- Servers are installed via Nix (runtimePkgs in plugins.nix) +-- Uses vim.lsp.config / vim.lsp.enable instead of deprecated lspconfig framework + +-- Diagnostic appearance +vim.diagnostic.config({ + underline = true, + update_in_insert = false, + virtual_text = { + spacing = 4, + source = "if_many", + prefix = "●", + }, + severity_sort = true, + signs = { + text = { + [vim.diagnostic.severity.ERROR] = " ", + [vim.diagnostic.severity.WARN] = " ", + [vim.diagnostic.severity.HINT] = " ", + [vim.diagnostic.severity.INFO] = " ", + }, + }, +}) + +-- Common LSP keymaps (attached via LspAttach autocmd) +vim.api.nvim_create_autocmd("LspAttach", { + group = vim.api.nvim_create_augroup("lsp_keymaps", { clear = true }), + callback = function(event) + local map = function(mode, lhs, rhs, desc) + vim.keymap.set(mode, lhs, rhs, { buffer = event.buf, desc = desc }) + end + map("n", "gd", vim.lsp.buf.definition, "Go to definition") + map("n", "gr", vim.lsp.buf.references, "References") + map("n", "gD", vim.lsp.buf.declaration, "Go to declaration") + map("n", "gI", vim.lsp.buf.implementation, "Go to implementation") + map("n", "gy", vim.lsp.buf.type_definition, "Go to type definition") + map("n", "K", vim.lsp.buf.hover, "Hover") + map("n", "gK", vim.lsp.buf.signature_help, "Signature help") + map("i", "", vim.lsp.buf.signature_help, "Signature help") + map("n", "ca", vim.lsp.buf.code_action, "Code action") + map("n", "cr", vim.lsp.buf.rename, "Rename") + map("n", "cl", "checkhealth lsp", "LSP info") + end, +}) + +-- Capabilities (with blink.cmp completion support) +local capabilities = vim.lsp.protocol.make_client_capabilities() +local ok, blink = pcall(require, "blink.cmp") +if ok then + capabilities = blink.get_lsp_capabilities(capabilities) +end + +-- ── Server configurations ────────────────────────────────────────────────── + +-- C/C++ (clangd) +vim.lsp.config("clangd", { + cmd = { "clangd", "--background-index", "--clang-tidy", "--header-insertion=iwyu" }, + capabilities = capabilities, +}) + +-- Python +vim.lsp.config("pyright", { + capabilities = capabilities, +}) + +-- Nix +vim.lsp.config("nil_ls", { + capabilities = capabilities, + settings = { + ["nil"] = { + formatting = { command = { "nixpkgs-fmt" } }, + }, + }, +}) + +-- Bash +vim.lsp.config("bashls", { + capabilities = capabilities, +}) + +-- Lua +vim.lsp.config("lua_ls", { + capabilities = capabilities, + settings = { + Lua = { + workspace = { checkThirdParty = false }, + codeLens = { enable = true }, + completion = { callSnippet = "Replace" }, + diagnostics = { globals = { "vim" } }, + }, + }, +}) + +-- Rust +vim.lsp.config("rust_analyzer", { + capabilities = capabilities, + settings = { + ["rust-analyzer"] = { + checkOnSave = { command = "clippy" }, + }, + }, +}) + +-- Go +vim.lsp.config("gopls", { + capabilities = capabilities, + settings = { + gopls = { + gofumpt = true, + analyses = { unusedparams = true }, + staticcheck = true, + }, + }, +}) + +-- TypeScript +vim.lsp.config("ts_ls", { + capabilities = capabilities, +}) + +-- Enable all configured servers +vim.lsp.enable({ + "clangd", + "pyright", + "nil_ls", + "bashls", + "lua_ls", + "rust_analyzer", + "gopls", + "ts_ls", +}) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/bufferline.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/bufferline.lua new file mode 100644 index 0000000..2a925a3 --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/bufferline.lua @@ -0,0 +1,16 @@ +-- Buffer/tab bar +require("bufferline").setup({ + options = { + close_command = "bdelete! %d", + diagnostics = "nvim_lsp", + always_show_bufferline = false, + offsets = { + { + filetype = "neo-tree", + text = "Neo-tree", + highlight = "Directory", + text_align = "left", + }, + }, + }, +}) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/colorscheme.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/colorscheme.lua new file mode 100644 index 0000000..5d27cc6 --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/colorscheme.lua @@ -0,0 +1,17 @@ +-- Colorscheme: tokyonight (LazyVim default) +require("tokyonight").setup({ + style = "moon", + transparent = false, + terminal_colors = true, + styles = { + comments = { italic = true }, + keywords = { italic = true }, + sidebars = "dark", + floats = "dark", + }, +}) + +vim.cmd.colorscheme("tokyonight") + +-- Make window split borders brighter +vim.api.nvim_set_hl(0, "WinSeparator", { fg = "#7aa2f7", bold = true }) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/lualine.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/lualine.lua new file mode 100644 index 0000000..3522201 --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/lualine.lua @@ -0,0 +1,26 @@ +-- Statusline +require("lualine").setup({ + options = { + theme = "auto", + globalstatus = true, + disabled_filetypes = { statusline = { "dashboard", "alpha", "ministarter", "snacks_dashboard" } }, + }, + sections = { + lualine_a = { "mode" }, + lualine_b = { "branch" }, + lualine_c = { + { "diagnostics" }, + { "filetype", icon_only = true, separator = "", padding = { left = 1, right = 0 } }, + { "filename", path = 1 }, + }, + lualine_x = { "diff" }, + lualine_y = { + { "progress", separator = " ", padding = { left = 1, right = 0 } }, + { "location", padding = { left = 0, right = 1 } }, + }, + lualine_z = { + function() return " " .. os.date("%R") end, + }, + }, + extensions = { "neo-tree" }, +}) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/noice.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/noice.lua new file mode 100644 index 0000000..7c52520 --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/noice.lua @@ -0,0 +1,38 @@ +-- Modern UI for cmdline, messages, and popupmenu +require("noice").setup({ + cmdline = { + view = "cmdline_popup", + }, + views = { + cmdline_popup = { + position = { + row = "75%", + col = "50%", + }, + }, + }, + lsp = { + override = { + ["vim.lsp.util.convert_input_to_markdown_lines"] = true, + ["vim.lsp.util.stylize_markdown"] = true, + }, + }, + routes = { + { + filter = { + event = "msg_show", + any = { + { find = "%d+L, %d+B" }, + { find = "; after #%d+" }, + { find = "; before #%d+" }, + }, + }, + view = "mini", + }, + }, + presets = { + bottom_search = true, + command_palette = true, + long_message_to_split = true, + }, +}) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/snacks.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/snacks.lua new file mode 100644 index 0000000..acd106e --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/snacks.lua @@ -0,0 +1,11 @@ +-- Snacks.nvim — dashboard, indent guides, notifications, etc. +require("snacks").setup({ + dashboard = { enabled = true }, + indent = { enabled = true }, + input = { enabled = true }, + notifier = { enabled = true }, + scope = { enabled = true }, + scroll = { enabled = true }, + statuscolumn = { enabled = true }, + words = { enabled = true }, +}) diff --git a/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/which-key.lua b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/which-key.lua new file mode 100644 index 0000000..1c7027d --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/nvim/lua/plugins/ui/which-key.lua @@ -0,0 +1,16 @@ +-- Keybinding popup hints +require("which-key").setup({ + plugins = { spelling = true }, +}) + +-- Register group labels +require("which-key").add({ + { "b", group = "buffers" }, + { "c", group = "code" }, + { "f", group = "file/find" }, + { "g", group = "git" }, + { "gh", group = "git hunks" }, + { "s", group = "search" }, + { "u", group = "ui" }, + { "x", group = "diagnostics" }, +}) diff --git a/modules/home/editors/neovim/dotfiles/plugins.nix b/modules/home/editors/neovim/dotfiles/plugins.nix new file mode 100644 index 0000000..8f530f6 --- /dev/null +++ b/modules/home/editors/neovim/dotfiles/plugins.nix @@ -0,0 +1,86 @@ +# nix-wrapper-modules Neovim configuration +# Declares plugins (specs) and runtime packages (LSPs, formatters, linters). +# The actual plugin configuration lives in Lua files under dotfiles/nvim/lua/ +# +# To add/remove plugins or LSP servers: edit this file → nixos-rebuild switch +# To change keymaps, options, plugin config: edit Lua files → restart nvim +{ pkgs, lib }: +{ + + # ── UI Plugins ───────────────────────────────────────────────────────────── + + specs.ui = with pkgs.vimPlugins; [ + tokyonight-nvim # colorscheme + lualine-nvim # statusline + bufferline-nvim # buffer/tab bar + nvim-web-devicons # file icons (nerd font) + noice-nvim # cmdline, messages, popupmenu UI + nui-nvim # UI component library (noice dep) + nvim-notify # notification manager + snacks-nvim # dashboard, indent guides, git browse, etc. + which-key-nvim # keybinding popup hints + dressing-nvim # improved vim.ui.select / vim.ui.input + ]; + + # ── Editor Plugins ───────────────────────────────────────────────────────── + + specs.editor = with pkgs.vimPlugins; [ + neo-tree-nvim # file explorer sidebar + telescope-nvim # fuzzy finder + telescope-fzf-native-nvim # native fzf sorter for telescope + gitsigns-nvim # git change indicators in sign column + trouble-nvim # diagnostics / quickfix list + todo-comments-nvim # highlight TODO/FIXME/HACK/NOTE + flash-nvim # motion / jump plugin + ]; + + # ── Coding Plugins ───────────────────────────────────────────────────────── + + specs.coding = with pkgs.vimPlugins; [ + (nvim-treesitter.withAllGrammars) # syntax highlighting + text objects + nvim-lspconfig # LSP server configuration + blink-cmp # autocompletion engine + conform-nvim # formatting on save + nvim-lint # async linting + mini-nvim # mini.pairs, mini.surround, mini.ai, etc. + luasnip # snippet engine + ]; + + # ── Dependency Plugins ───────────────────────────────────────────────────── + + specs.deps = with pkgs.vimPlugins; [ + plenary-nvim # utility library (telescope, gitsigns dep) + ]; + + # ── Runtime Packages ─────────────────────────────────────────────────────── + # These are added to Neovim's $PATH (not installed globally). + # Neovim's LSP, formatters, and linters will find them automatically. + + runtimePkgs = with pkgs; [ + # ── LSP servers ── + clang-tools # C/C++ (clangd + clang-format) + pyright # Python + nil # Nix + bash-language-server # Bash + lua-language-server # Lua + rust-analyzer # Rust + gopls # Go + typescript-language-server # TypeScript + + # ── Formatters ── + stylua # Lua + nixpkgs-fmt # Nix + black # Python + gofumpt # Go + prettier # TS/JS/HTML/CSS + + # ── Linters ── + shellcheck # Bash/Shell + + # ── Tools ── + ripgrep # fast grep (telescope backend) + fd # fast find (telescope backend) + tree-sitter # tree-sitter CLI (grammar compilation) + wl-clipboard # clipboard provider (Wayland) + ]; +} diff --git a/modules/home/editors/neovim/dotfiles/plugins/airline.nix b/modules/home/editors/neovim/dotfiles/plugins/airline.nix deleted file mode 100644 index 5af2f79..0000000 --- a/modules/home/editors/neovim/dotfiles/plugins/airline.nix +++ /dev/null @@ -1,16 +0,0 @@ -{ ... }: -let -in { - config.programs.nixvim = { - plugins = { - airline = { - enable = true; - settings = { - theme = "catppuccin"; - - powerline_fonts = 1; - }; - }; - }; - }; -} diff --git a/modules/home/editors/neovim/dotfiles/plugins/neoscroll.nix b/modules/home/editors/neovim/dotfiles/plugins/neoscroll.nix deleted file mode 100644 index 397cd60..0000000 --- a/modules/home/editors/neovim/dotfiles/plugins/neoscroll.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ ... }: -let -in { - config.programs.nixvim = { - plugins = { - neoscroll = { - enable = true; - }; - }; - }; -} diff --git a/modules/home/editors/neovim/dotfiles/plugins/neotree.nix b/modules/home/editors/neovim/dotfiles/plugins/neotree.nix deleted file mode 100644 index 0772f08..0000000 --- a/modules/home/editors/neovim/dotfiles/plugins/neotree.nix +++ /dev/null @@ -1,35 +0,0 @@ -{ ... }: -let -in { - config.programs.nixvim = { - plugins = { - neo-tree = { - enable = true; - }; - }; - keymaps = [ - { - mode = "n"; - key = "e"; - action = "Neotree toggle"; - options.desc = "Toggle explorer"; - } - { - mode = "n"; - key = "o"; - options.desc = "Toggle explorer focus"; - - # https://github.com/AstroNvim/AstroNvim/blob/v4.7.7/lua/astronvim/plugins/neo-tree.lua#L12-L18 - action.__raw = '' - function() - if vim.bo.filetype == "neo-tree" then - vim.cmd.wincmd "p" - else - vim.cmd.Neotree "focus" - end - end - ''; - } - ]; - }; -} diff --git a/modules/home/editors/neovim/dotfiles/plugins/noice.nix b/modules/home/editors/neovim/dotfiles/plugins/noice.nix deleted file mode 100644 index dfda303..0000000 --- a/modules/home/editors/neovim/dotfiles/plugins/noice.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ ... }: -let -in { - config.programs.nixvim = { - plugins = { - noice = { - enable = false; - }; - }; - }; -} diff --git a/modules/home/editors/neovim/dotfiles/plugins/telescope.nix b/modules/home/editors/neovim/dotfiles/plugins/telescope.nix deleted file mode 100644 index 71b5662..0000000 --- a/modules/home/editors/neovim/dotfiles/plugins/telescope.nix +++ /dev/null @@ -1,39 +0,0 @@ -{ ... }: -let -in { - config.programs.nixvim = { - plugins = { - telescope = { - enable = true; - extensions = { - fzf-native = { - enable = true; - }; - }; - }; - - }; - keymaps = [ - { - mode = "n"; - key = "ff"; - action = "Telescope find_files"; - } - { - mode = "n"; - key = "fg"; - action = "Telescope live_grep"; - } - { - mode = "n"; - key = "fb"; - action = "Telescope buffers"; - } - { - mode = "n"; - key = "fh"; - action = "Telescope help_tags"; - } - ]; - }; -} diff --git a/modules/home/editors/neovim/dotfiles/plugins/web-devicons.nix b/modules/home/editors/neovim/dotfiles/plugins/web-devicons.nix deleted file mode 100644 index fcc6c15..0000000 --- a/modules/home/editors/neovim/dotfiles/plugins/web-devicons.nix +++ /dev/null @@ -1,11 +0,0 @@ -{ ... }: -let -in { - config.programs.nixvim = { - plugins = { - web-devicons = { - enable = true; - }; - }; - }; -} diff --git a/modules/home/editors/neovim/dotfiles/plugins/which-key.nix b/modules/home/editors/neovim/dotfiles/plugins/which-key.nix deleted file mode 100644 index cc6c541..0000000 --- a/modules/home/editors/neovim/dotfiles/plugins/which-key.nix +++ /dev/null @@ -1,81 +0,0 @@ -{ ... }: -let - icons = (import ../utils/icons.nix).icons; -in -{ - config.programs.nixvim = { - plugins = { - which-key = { - enable = true; - settings.icons.group = ""; - - settings.win.border = "single"; - - settings.disable.ft = [ - "TelescopePrompt" - "neo-tree" - "neo-tree-popup" - ]; - - settings.spec = [ - { - __unkeyed-1 = "b"; - group = "Buffers"; - icon = "󰓩 "; - } - { - __unkeyed = "c"; - group = "Codesnap"; - icon = "󰄄 "; - mode = "v"; - } - { - __unkeyed-1 = "bs"; - group = "Sort"; - icon = "󰒺 "; - } - { - __unkeyed-1 = [ - { - __unkeyed-1 = "f"; - group = "Normal Visual Group"; - } - { - __unkeyed-1 = "f"; - group = "Normal Visual Group in Group"; - } - ]; - mode = [ - "n" - "v" - ]; - } - { - __unkeyed-1 = "w"; - group = "windows"; - proxy = ""; - } - { - __unkeyed-1 = "cS"; - __unkeyed-2 = "CodeSnapSave"; - desc = "Save"; - mode = "v"; - } - { - __unkeyed-1 = "db"; - __unkeyed-2 = { - __raw = '' - function() - require("dap").toggle_breakpoint() - end - ''; - }; - desc = "Breakpoint toggle"; - mode = "n"; - silent = true; - } - ]; - }; - }; - }; -} diff --git a/modules/home/editors/neovim/dotfiles/utils/icons.nix b/modules/home/editors/neovim/dotfiles/utils/icons.nix deleted file mode 100644 index 7ab059e..0000000 --- a/modules/home/editors/neovim/dotfiles/utils/icons.nix +++ /dev/null @@ -1,62 +0,0 @@ -{ - icons = { - ActiveLSP = ""; - ActiveTS = ""; - ArrowLeft = ""; - ArrowRight = ""; - Bookmarks = ""; - BufferClose = "󰅖"; - DapBreakpoint = ""; - DapBreakpointCondition = ""; - DapBreakpointRejected = ""; - DapLogPoint = "󰛿"; - DapStopped = "󰁕"; - Debugger = ""; - DefaultFile = "󰈙"; - Diagnostic = "󰒡"; - DiagnosticError = ""; - DiagnosticHint = "󰌵"; - DiagnosticInfo = "󰋼"; - DiagnosticWarn = ""; - Ellipsis = "…"; - Environment = ""; - FileNew = ""; - FileModified = ""; - FileReadOnly = ""; - FoldClosed = ""; - FoldOpened = ""; - FoldSeparator = " "; - FolderClosed = ""; - FolderEmpty = ""; - FolderOpen = ""; - Git = "󰊢"; - GitAdd = ""; - GitBranch = ""; - GitChange = ""; - GitConflict = ""; - GitDelete = ""; - GitIgnored = "◌"; - GitRenamed = "➜"; - GitSign = "▎"; - GitStaged = "✓"; - GitUnstaged = "✗"; - GitUntracked = "★"; - LSPLoading1 = ""; - LSPLoading2 = "󰀚"; - LSPLoading3 = ""; - MacroRecording = ""; - Package = "󰏖"; - Paste = "󰅌"; - Refresh = ""; - Search = ""; - Selected = "❯"; - Session = "󱂬"; - Sort = "󰒺"; - Spellcheck = "󰓆"; - Tab = "󰓩"; - TabClose = "󰅙"; - Terminal = ""; - Window = ""; - WordFile = "󰈭"; - }; -} diff --git a/modules/home/editors/neovim/neovim.nix b/modules/home/editors/neovim/neovim.nix index 5b96676..1fc8da1 100644 --- a/modules/home/editors/neovim/neovim.nix +++ b/modules/home/editors/neovim/neovim.nix @@ -1,33 +1,35 @@ -# Neovim editor with nixvim configuration +# Neovim editor with nix-wrapper-modules (Lua-first config) +# Plugins and LSPs are managed by Nix; configuration lives as standard Lua files +# that can be edited and reloaded instantly without nixos-rebuild. { lib, pkgs, inputs, ... }@args: +let + # Import plugin/LSP declarations + pluginConfig = import ./dotfiles/plugins.nix { inherit pkgs lib; }; + + # Build a wrapped neovim with all plugins and runtime tools baked in + # NOTE: NixOS pkgs can have _type = "if" (from mkIf in nixpkgs.config), + # which causes nix-wrapper-modules to misinterpret pkgs as a conditional. + # Override _type back to "pkgs" to fix the type check. + wrappedNeovim = inputs.nix-wrapper-modules.wrappers.neovim.wrap { + pkgs = pkgs // { _type = "pkgs"; }; + inherit (pluginConfig) specs runtimePkgs; + }; +in lib.my.mkModuleV2 args { platforms = [ "linux" "darwin" ]; - description = "Neovim editor with nixvim configuration"; - imports = [ - ./dotfiles/colorschema.nix - ./dotfiles/general.nix - ./dotfiles/keymaps.nix - ./dotfiles/plugins/airline.nix - ./dotfiles/plugins/neoscroll.nix - ./dotfiles/plugins/neotree.nix - ./dotfiles/plugins/noice.nix - ./dotfiles/plugins/telescope.nix - ./dotfiles/plugins/which-key.nix - ./dotfiles/plugins/web-devicons.nix - ]; - systemModule = { - # Enable nixvim (system-level NixOS option, not home-manager) - # Must be wrapped in allSystems so mkModuleV2 unwraps it correctly - allSystems.programs.nixvim = { - enable = true; - # Suppress the nixpkgs.follows mismatch warning — we intentionally - # use our pinned nixpkgs rather than nixvim's bundled one. - nixpkgs.source = inputs.nixpkgs; - }; - }; + description = "Neovim editor with Lua-first configuration"; + module = { - # Keep plain Neovim available while nixvim plugin pack is disabled. - allSystems.home.packages = with pkgs; [ ripgrep fzf ]; + # The wrapped neovim has plugins + LSPs on its PATH. + # ripgrep/fzf/fd also added globally for shell usage. + allSystems.home.packages = [ wrappedNeovim ] ++ (with pkgs; [ ripgrep fzf fd ]); + }; + + # Symlink dotfiles/nvim → ~/.config/nvim for live editing + # Edit Lua configs → restart nvim → changes apply (no rebuild needed) + dotfiles = { + path = "nvim"; + source = "modules/home/editors/neovim/dotfiles/nvim"; }; }