From cc9a5dc0f5e260273325482f7729519ee9dfcaf6 Mon Sep 17 00:00:00 2001 From: "RingOfStorms (Joshua Bell)" Date: Thu, 22 Jan 2026 16:54:45 -0600 Subject: [PATCH] Refactor plugin layout, add AI autocomplete and direnv, update docs --- README.md | 153 ++++- flake.lock | 281 +++++---- flake.nix | 33 +- init.lua | 16 +- lua/plugins/cmp_autocompletion.lua | 111 ---- lua/plugins/comments_support.lua | 45 -- lua/plugins/completion.lua | 74 +++ lua/plugins/diagnostics.lua | 21 + lua/plugins/direnv.lua | 7 + .../{conform_formatter.lua => formatting.lua} | 0 lua/plugins/lazydev.lua | 12 + lua/plugins/{lint.lua => linting.lua} | 0 lua/plugins/llm_autocomplete.lua | 61 ++ lua/plugins/lsp.lua | 80 ++- lua/plugins/mini.lua | 63 +++ lua/plugins/surround.lua | 4 - lua/plugins/treesitter.lua | 108 ++-- lua/plugins/whichkey.lua | 1 + lua/tools/init.lua | 4 +- todo.md | 535 ++++++++++++++++++ 20 files changed, 1195 insertions(+), 414 deletions(-) delete mode 100644 lua/plugins/cmp_autocompletion.lua delete mode 100644 lua/plugins/comments_support.lua create mode 100644 lua/plugins/completion.lua create mode 100644 lua/plugins/diagnostics.lua create mode 100644 lua/plugins/direnv.lua rename lua/plugins/{conform_formatter.lua => formatting.lua} (100%) create mode 100644 lua/plugins/lazydev.lua rename lua/plugins/{lint.lua => linting.lua} (100%) create mode 100644 lua/plugins/llm_autocomplete.lua create mode 100644 lua/plugins/mini.lua delete mode 100644 lua/plugins/surround.lua create mode 100644 todo.md diff --git a/README.md b/README.md index 45c0bef..8e24e55 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,10 @@ Goals: -- Works with or without nix (have not verified non nix yet...) +- Works with or without nix - LSP integration with the current project's settings if available - -Old pre nix config: https://git.joshuabell.xyz/nvim/~files/40eadc9b714fa29c5b28aca49f77c1ea62141763 for reference +- Lean and fast startup with lazy loading +- Project-driven tooling via direnv and devShells ## Running @@ -30,11 +30,9 @@ environment.systemPackages = with pkgs; [ ### Without Nix -TODO update this section - - Must have all required programs installed and available on path - - neovim >= 0.5 - - Evertying listed in flake.nix `runtime dependencies` variable near the top of the file + - neovim >= 0.11 (required for native LSP config) + - Everything listed in flake.nix `runtimeDependenciesCore` variable - These must be available on the path - Treesitter/Lazy/Mason will install all other requirements needed on other systems @@ -60,27 +58,144 @@ rm -rf ~/.local/share/nvim rm -rf ~/.local/state/nvim ``` +## Project LSP Setup + +This config uses a "lean core" approach where most LSPs come from your project's devShell via direnv. + +### How It Works + +1. **Core tools** (ripgrep, fd, lua-language-server, nil, etc.) are always available +2. **direnv.vim** automatically loads your project's `.envrc` / `devShell` environment +3. **Smart detection** warns you if an expected LSP is missing for a filetype + +### Example Project flake.nix + +```nix +{ + inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; + + outputs = { nixpkgs, ... }: + let + pkgs = nixpkgs.legacyPackages.x86_64-linux; + in { + devShells.x86_64-linux.default = pkgs.mkShell { + packages = with pkgs; [ + # Your project's LSPs + typescript-language-server + nodePackages.prettier + eslint_d + + # Your project's tools + nodejs_22 + pnpm + ]; + }; + }; +} +``` + +Then create `.envrc`: +```sh +use flake +``` + +And run `direnv allow` in your project directory. + +## Local AI Autocomplete + +This config supports local AI-powered code completion via [llama.vim](https://github.com/ggml-org/llama.vim). + +### Setup + +1. Install llama.cpp: + ```sh + # macOS + brew install llama.cpp + + # Or build from source + git clone https://github.com/ggml-org/llama.cpp + cd llama.cpp && make + ``` + +2. Download a FIM-capable model (e.g., sweep-next-edit-1.5B): + ```sh + # From HuggingFace + wget https://huggingface.co/sweepai/sweep-next-edit-1.5B-GGUF/resolve/main/sweep-next-edit-Q8_0.gguf + ``` + +3. Start llama-server: + ```sh + llama-server -m sweep-next-edit-Q8_0.gguf --port 8012 --fim-qwen-7b-default + ``` + +4. Neovim will auto-detect the server and enable completions + +### Usage + +- **Tab** - Accept completion +- **Shift-Tab** - Accept first line only +- **Ctrl-F** - Toggle FIM manually +- **`,a`** - Toggle AI autocomplete on/off + +### Recommended Models by VRAM + +| VRAM | Recommended Model | +|------|-------------------| +| >64GB | qwen2.5-coder-32b | +| >16GB | qwen2.5-coder-7b | +| <16GB | qwen2.5-coder-3b | +| <8GB | sweep-next-edit-1.5b | + +## Key Plugins + +| Category | Plugin | Description | +|----------|--------|-------------| +| Completion | blink.cmp | Fast async completion with LSP, snippets, buffer | +| LSP | nvim-lspconfig | Native LSP configurations | +| Diagnostics | trouble.nvim | Pretty diagnostics and quickfix lists | +| Formatting | conform.nvim | Fast formatter integration | +| Linting | nvim-lint | Async linter integration | +| AI | llama.vim | Local LLM code completion | +| Utilities | mini.nvim | Surround, comment, pairs, text objects | +| Files | nvim-tree, telescope | File browsing and fuzzy finding | + +## Keybindings + +### LSP +- `gd` - Go to definition +- `gr` - Go to references +- `gI` - Go to implementation +- `K` - Hover documentation +- `la` - Code action +- `lr` - Rename + +### Diagnostics (Trouble) +- `xx` - Toggle diagnostics +- `xX` - Buffer diagnostics only +- `xs` - Document symbols +- `xq` - Quickfix list + +### Comments (mini.comment) +- `gc{motion}` - Toggle comment +- `gcc` - Toggle line comment +- `/` - Toggle comment (preserved binding) + +### Surround (mini.surround) +- `gsa{motion}{char}` - Add surrounding +- `gsd{char}` - Delete surrounding +- `gsr{old}{new}` - Replace surrounding + ## NOTES/TODOS -- See what linters/formaters to add or are the LSP's enough? - CSPELL/spelling linter +- Consider mini-align for alignment FUTURE - Make a new HTTP plugin for running curl commands from .http files - - similar to est-nvim/rest.nvim but support streaming etc and show command output -- Execute selected command and open output into a buffer/popup window? cx + - similar to rest-nvim/rest.nvim but support streaming etc and show command output - generate command, like scratch open a popup of things that can be generated. UUID/other stuff? -- - Checkout cargo-bloat, cargo-cache, cargo-outdated - memcache sccache - For scratches, just make an input box for custom extension rather than predefined list -- freaking learn to use surround more often -- make my own session saving impl - - Only save visible buffers/tabs/splits - - per branch per directory - - something like but fully managed -- copilot? local llm? - check out - - - - - diff --git a/flake.lock b/flake.lock index b67757d..e9fd9a2 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1766309749, - "narHash": "sha256-3xY8CZ4rSnQ0NqGhMKAy5vgC+2IVK0NoVEzDoOh4DA4=", + "lastModified": 1769018530, + "narHash": "sha256-MJ27Cy2NtBEV5tsK+YraYr2g851f3Fl1LpNHDzDX15c=", "owner": "nixos", "repo": "nixpkgs", - "rev": "a6531044f6d0bef691ea18d4d4ce44d0daa6e816", + "rev": "88d3861acdd3d2f0e361767018218e51810df8a1", "type": "github" }, "original": { @@ -32,22 +32,6 @@ "type": "github" } }, - "nvim_plugin-CopilotC-Nvim/CopilotChat.nvim": { - "flake": false, - "locked": { - "lastModified": 1766398838, - "narHash": "sha256-pO+bnwywDmhEpmU3Zw2VCAT8uLEgRlpHcAfW9NwqWis=", - "owner": "CopilotC-Nvim", - "repo": "CopilotChat.nvim", - "rev": "ed94e56ee8292f5df351e17709ff4b178ca84200", - "type": "github" - }, - "original": { - "owner": "CopilotC-Nvim", - "repo": "CopilotChat.nvim", - "type": "github" - } - }, "nvim_plugin-JoosepAlviste/nvim-ts-context-commentstring": { "flake": false, "locked": { @@ -67,11 +51,11 @@ "nvim_plugin-L3MON4D3/LuaSnip": { "flake": false, "locked": { - "lastModified": 1762213057, - "narHash": "sha256-Pil9m8zN3XzMtPT8spdr78dzkMW7dcpVnbWzie6524A=", + "lastModified": 1768781124, + "narHash": "sha256-3beTsZPT2EwzAVhEzqNhFRnDAU7C7GlzFFymY3aNp9M=", "owner": "L3MON4D3", "repo": "LuaSnip", - "rev": "3732756842a2f7e0e76a7b0487e9692072857277", + "rev": "dae4f5aaa3574bd0c2b9dd20fb9542a02c10471c", "type": "github" }, "original": { @@ -83,11 +67,11 @@ "nvim_plugin-MeanderingProgrammer/render-markdown.nvim": { "flake": false, "locked": { - "lastModified": 1765914395, - "narHash": "sha256-A7pm8sBQWsZl3Kc7JBh3gBUyKb6GfJ5J0zfn3mSGjKs=", + "lastModified": 1768589366, + "narHash": "sha256-kKvIivCNe6HlGqiChySeqEHRB0rj6ipKwjko4ix4tRw=", "owner": "MeanderingProgrammer", "repo": "render-markdown.nvim", - "rev": "07d088bf8bdadd159eb807b90eaee86a4778383f", + "rev": "c54380dd4d8d1738b9691a7c349ecad7967ac12e", "type": "github" }, "original": { @@ -163,11 +147,11 @@ "nvim_plugin-b0o/schemastore.nvim": { "flake": false, "locked": { - "lastModified": 1766167236, - "narHash": "sha256-+Z1foMyKMxyMmYqmyu1KWiyL4Fc0Zm2SYV7RoZ9Ut2I=", + "lastModified": 1768946435, + "narHash": "sha256-nv8ZAqrQBe0ckmHqeI4HLLOKphwxjq7v3OAShQ7HtcY=", "owner": "b0o", "repo": "schemastore.nvim", - "rev": "8b92ea89835b8e5dbc779a675ebb0e5fcb9a1993", + "rev": "a0375eb6f7f944723162ef41c200ac6b364f53ac", "type": "github" }, "original": { @@ -179,11 +163,11 @@ "nvim_plugin-catppuccin/nvim": { "flake": false, "locked": { - "lastModified": 1765701669, - "narHash": "sha256-8GKpGGdeBwxuMrheojyl162CzUntRcq9AktQVmKbpuI=", + "lastModified": 1767886506, + "narHash": "sha256-cZ6VeF69s0eQ9I7Tz8MoEKuF9w+TbA94vXj2EuDoSgU=", "owner": "catppuccin", "repo": "nvim", - "rev": "ce8d176faa4643e026e597ae3c31db59b63cef09", + "rev": "beaf41a30c26fd7d6c386d383155cbd65dd554cd", "type": "github" }, "original": { @@ -195,11 +179,11 @@ "nvim_plugin-chrisgrieser/nvim-early-retirement": { "flake": false, "locked": { - "lastModified": 1766186911, - "narHash": "sha256-COYpFOZTMGpZVfSJFMix/6TM5Eeemngcx1iukMa2nDE=", + "lastModified": 1767720082, + "narHash": "sha256-2fQsVQUAuKX0uz+umM7VCUFPRKmIr7L9KQIgnlo3bG0=", "owner": "chrisgrieser", "repo": "nvim-early-retirement", - "rev": "86edd80026e4eea2cef7d1e5dadcf34432e6098d", + "rev": "79ea1568df53986e0d9f4d36fd542933a34b2e61", "type": "github" }, "original": { @@ -224,6 +208,38 @@ "type": "github" } }, + "nvim_plugin-direnv/direnv.vim": { + "flake": false, + "locked": { + "lastModified": 1701514458, + "narHash": "sha256-Lwwm95UEkS8Q0Qsoh10o3sFn48wf7v7eCX/FJJV1HMI=", + "owner": "direnv", + "repo": "direnv.vim", + "rev": "ab2a7e08dd630060cd81d7946739ac7442a4f269", + "type": "github" + }, + "original": { + "owner": "direnv", + "repo": "direnv.vim", + "type": "github" + } + }, + "nvim_plugin-echasnovski/mini.nvim": { + "flake": false, + "locked": { + "lastModified": 1769086673, + "narHash": "sha256-dyKTxP4f6ZZ6MN4nz87X+K1d/WxhwnQ6+HxHSKgqacM=", + "owner": "echasnovski", + "repo": "mini.nvim", + "rev": "9b935c218ddba02e5dc75c94f90143bce1f7c646", + "type": "github" + }, + "original": { + "owner": "echasnovski", + "repo": "mini.nvim", + "type": "github" + } + }, "nvim_plugin-folke/lazy.nvim": { "flake": false, "locked": { @@ -240,19 +256,35 @@ "type": "github" } }, - "nvim_plugin-folke/neodev.nvim": { + "nvim_plugin-folke/lazydev.nvim": { "flake": false, "locked": { - "lastModified": 1720260306, - "narHash": "sha256-hOjzlo/IqmV8tYjGwfmcCPEmHYsWnEIwtHZdhpwA1kM=", + "lastModified": 1762423570, + "narHash": "sha256-1g1PLFR3bc++NimbrRpoOMZyqYWHeX6pDoxsiuoJHus=", "owner": "folke", - "repo": "neodev.nvim", - "rev": "46aa467dca16cf3dfe27098042402066d2ae242d", + "repo": "lazydev.nvim", + "rev": "5231c62aa83c2f8dc8e7ba957aa77098cda1257d", "type": "github" }, "original": { "owner": "folke", - "repo": "neodev.nvim", + "repo": "lazydev.nvim", + "type": "github" + } + }, + "nvim_plugin-folke/trouble.nvim": { + "flake": false, + "locked": { + "lastModified": 1761919011, + "narHash": "sha256-6U/KWjvRMxWIxcsI2xNU/ltfgkaFG4E3BdzC7brK/DI=", + "owner": "folke", + "repo": "trouble.nvim", + "rev": "bd67efe408d4816e25e8491cc5ad4088e708a69a", + "type": "github" + }, + "original": { + "owner": "folke", + "repo": "trouble.nvim", "type": "github" } }, @@ -272,6 +304,22 @@ "type": "github" } }, + "nvim_plugin-ggml-org/llama.vim": { + "flake": false, + "locked": { + "lastModified": 1768976621, + "narHash": "sha256-aeA2YDbORc/4j3ANoe1YDizh7zknGif1scv6mMTVa0E=", + "owner": "ggml-org", + "repo": "llama.vim", + "rev": "85ec507281e246ad3e4b1d945ed92eea0745f0fd", + "type": "github" + }, + "original": { + "owner": "ggml-org", + "repo": "llama.vim", + "type": "github" + } + }, "nvim_plugin-hrsh7th/cmp-buffer": { "flake": false, "locked": { @@ -323,11 +371,11 @@ "nvim_plugin-hrsh7th/nvim-cmp": { "flake": false, "locked": { - "lastModified": 1763258674, - "narHash": "sha256-Z6F8auKq1jSgGoPhV4RbkB1YTexnolSbEjpa/JJI/Fc=", + "lastModified": 1767368202, + "narHash": "sha256-gwuiUgz3UEFpaKs79BSWS4qkwOi+XMHIDFdYRatWt0g=", "owner": "hrsh7th", "repo": "nvim-cmp", - "rev": "d97d85e01339f01b842e6ec1502f639b080cb0fc", + "rev": "85bbfad83f804f11688d1ab9486b459e699292d6", "type": "github" }, "original": { @@ -339,11 +387,11 @@ "nvim_plugin-j-hui/fidget.nvim": { "flake": false, "locked": { - "lastModified": 1766143069, - "narHash": "sha256-uy2Z6vn9UYDN7Dr7iuiTrualRQdmUT0dwHP/eZXA/uA=", + "lastModified": 1768329414, + "narHash": "sha256-Zap4UVicIvCaPqCMgdlnEAGbMzq1xM4uGpVqZL1iju0=", "owner": "j-hui", "repo": "fidget.nvim", - "rev": "64463022a1f2ff1318ab22a2ea4125ed9313a483", + "rev": "7fa433a83118a70fe24c1ce88d5f0bd3453c0970", "type": "github" }, "original": { @@ -371,11 +419,11 @@ "nvim_plugin-lewis6991/gitsigns.nvim": { "flake": false, "locked": { - "lastModified": 1764322768, - "narHash": "sha256-w3Q7nMFEbcjP6RmSTONg2Nw1dBXDEHnjQ69FuAPJRD8=", + "lastModified": 1768948049, + "narHash": "sha256-J9BvYVydeeoBj5Op+jGcI+i3IppdpoZ9jHbod0X1JFo=", "owner": "lewis6991", "repo": "gitsigns.nvim", - "rev": "5813e4878748805f1518cee7abb50fd7205a3a48", + "rev": "abf82a65f185bd54adc0679f74b7d6e1ada690c9", "type": "github" }, "original": { @@ -435,11 +483,11 @@ "nvim_plugin-mbbill/undotree": { "flake": false, "locked": { - "lastModified": 1759186837, - "narHash": "sha256-EWOH08KAWyoT9m45/B1d5aKQQJtd3k4orJbagVsxe08=", + "lastModified": 1766990053, + "narHash": "sha256-5/SQjSjQPYIK55P2rNrgn9psOSNpWpqJzkpWmjo8Itg=", "owner": "mbbill", "repo": "undotree", - "rev": "0f1c9816975b5d7f87d5003a19c53c6fd2ff6f7f", + "rev": "178d19e00a643f825ea11d581b1684745d0c4eda", "type": "github" }, "original": { @@ -451,11 +499,11 @@ "nvim_plugin-mfussenegger/nvim-lint": { "flake": false, "locked": { - "lastModified": 1766127989, - "narHash": "sha256-ysIoJ8uMAHu/OCemQ3yUYMhKIVnSDLQCvJH0SaGIOK4=", + "lastModified": 1767793421, + "narHash": "sha256-Ru+QklYFuwoeRvKlBXZcItuGvKDPbEq04sACKvTQds8=", "owner": "mfussenegger", "repo": "nvim-lint", - "rev": "7a64f4067065c16a355d40d0d599b8ca6b25de6d", + "rev": "ca6ea12daf0a4d92dc24c5c9ae22a1f0418ade37", "type": "github" }, "original": { @@ -467,11 +515,11 @@ "nvim_plugin-mrcjkb/rustaceanvim": { "flake": false, "locked": { - "lastModified": 1766276825, - "narHash": "sha256-dcXnh5SYPh1VRctTuCnuVPKFQuAI4XEvQasolCOv+Xw=", + "lastModified": 1768768642, + "narHash": "sha256-tIIPP6RVzJTwEI2V5E7MZRM69cUV4xlNvwnF9PD71l4=", "owner": "mrcjkb", "repo": "rustaceanvim", - "rev": "0fa0462a2d6c9629e0bd03d1902e6a1472ceac3e", + "rev": "d09c0639e7f68615db6845570241947198234cd6", "type": "github" }, "original": { @@ -483,11 +531,11 @@ "nvim_plugin-neovim/nvim-lspconfig": { "flake": false, "locked": { - "lastModified": 1766443238, - "narHash": "sha256-P95gPOwJ+rRofLb8iV5UOnh26to1I3sFrWGlGxHyz1M=", + "lastModified": 1769036040, + "narHash": "sha256-+KjXMTkVVVt3rpxQHRtrlT74DDsfRnPNUlqi/pvIMxg=", "owner": "neovim", "repo": "nvim-lspconfig", - "rev": "b34c08e0ea22bac67798f00238318fd16bd99b7c", + "rev": "419b082102fa813739588dd82e19a8b6b2442855", "type": "github" }, "original": { @@ -496,22 +544,6 @@ "type": "github" } }, - "nvim_plugin-numToStr/Comment.nvim": { - "flake": false, - "locked": { - "lastModified": 1717957420, - "narHash": "sha256-h0kPue5Eqd5aeu4VoLH45pF0DmWWo1d8SnLICSQ63zc=", - "owner": "numToStr", - "repo": "Comment.nvim", - "rev": "e30b7f2008e52442154b66f7c519bfd2f1e32acb", - "type": "github" - }, - "original": { - "owner": "numToStr", - "repo": "Comment.nvim", - "type": "github" - } - }, "nvim_plugin-nvim-lua/plenary.nvim": { "flake": false, "locked": { @@ -595,11 +627,11 @@ "nvim_plugin-nvim-telescope/telescope.nvim": { "flake": false, "locked": { - "lastModified": 1766268405, - "narHash": "sha256-O1rUiVKpDSvKMkZMFaEd8/ACcSgO/lfa1+Hc8uHbFOI=", + "lastModified": 1768858021, + "narHash": "sha256-u1IyXfbGG2WF08V2mkGfjinBD2glU6aik7GjTFxyAn0=", "owner": "nvim-telescope", "repo": "telescope.nvim", - "rev": "e709d31454ee6e6157f0537f861f797bd44c0bad", + "rev": "0d8b6eaa0b5ae6bb3d9785f7a3ba4a4c6c1b1af2", "type": "github" }, "original": { @@ -611,11 +643,11 @@ "nvim_plugin-nvim-tree/nvim-tree.lua": { "flake": false, "locked": { - "lastModified": 1766192360, - "narHash": "sha256-Br+r9f/2o0AkewnGm7kFNfl3uYm1Akkklof0Sm5AL2M=", + "lastModified": 1769045035, + "narHash": "sha256-bRgYf9A2FZmlRFP7ixkfZqtOF+rQ+ju0vQ52qfmvY0A=", "owner": "nvim-tree", "repo": "nvim-tree.lua", - "rev": "b8b44b6a2494d086a9177251a119f9daec6cace8", + "rev": "869fc957edd43962c4cc7d70f0dca087056534c8", "type": "github" }, "original": { @@ -627,11 +659,11 @@ "nvim_plugin-nvim-tree/nvim-web-devicons": { "flake": false, "locked": { - "lastModified": 1766287594, - "narHash": "sha256-ZdFRd0//C0Lle4cYIoAHBdz/yvQqmeylLNwvSifaWm4=", + "lastModified": 1768089403, + "narHash": "sha256-x1ujwUXnRolP9SRUD7/Pb4/AZu+3YpC6CfGuq3Bn6Ew=", "owner": "nvim-tree", "repo": "nvim-web-devicons", - "rev": "6788013bb9cb784e606ada44206b0e755e4323d7", + "rev": "803353450c374192393f5387b6a0176d0972b848", "type": "github" }, "original": { @@ -755,11 +787,11 @@ "nvim_plugin-stevearc/conform.nvim": { "flake": false, "locked": { - "lastModified": 1766346125, - "narHash": "sha256-Pp4bGTlZEqxHoHqVCEekDdg2jvNayxAuBReK4HJ6yGg=", + "lastModified": 1768760646, + "narHash": "sha256-M2mGNF8iARiQ6MzIFSSE/2BRDSj1+XEP/C44dwg8MQ8=", "owner": "stevearc", "repo": "conform.nvim", - "rev": "5420c4b5ea0aeb99c09cfbd4fd0b70d257b44f25", + "rev": "c2526f1cde528a66e086ab1668e996d162c75f4f", "type": "github" }, "original": { @@ -800,22 +832,6 @@ "type": "github" } }, - "nvim_plugin-tpope/vim-surround": { - "flake": false, - "locked": { - "lastModified": 1666730476, - "narHash": "sha256-DZE5tkmnT+lAvx/RQHaDEgEJXRKsy56KJY919xiH1lE=", - "owner": "tpope", - "repo": "vim-surround", - "rev": "3d188ed2113431cf8dac77be61b842acb64433d9", - "type": "github" - }, - "original": { - "owner": "tpope", - "repo": "vim-surround", - "type": "github" - } - }, "nvim_plugin-uga-rosa/ccc.nvim": { "flake": false, "locked": { @@ -835,11 +851,11 @@ "nvim_plugin-windwp/nvim-ts-autotag": { "flake": false, "locked": { - "lastModified": 1757545454, - "narHash": "sha256-nT2W5gKFEfzP7MztLjm7yqwam3ADk0svcMdLg2nmI/4=", + "lastModified": 1768909712, + "narHash": "sha256-XajbH3R1ONStQyYK6xQBE1cfGk3Y6tP/Mh9Ch90aKCk=", "owner": "windwp", "repo": "nvim-ts-autotag", - "rev": "c4ca798ab95b316a768d51eaaaee48f64a4a46bc", + "rev": "db15f2e0df2f5db916e511e3fffb682ef2f6354f", "type": "github" }, "original": { @@ -848,43 +864,10 @@ "type": "github" } }, - "nvim_plugin-zbirenbaum/copilot-cmp": { - "flake": false, - "locked": { - "lastModified": 1733947099, - "narHash": "sha256-erRL8bY/zuwuCZfttw+avTrFV7pjv2H6v73NzY2bymM=", - "owner": "zbirenbaum", - "repo": "copilot-cmp", - "rev": "15fc12af3d0109fa76b60b5cffa1373697e261d1", - "type": "github" - }, - "original": { - "owner": "zbirenbaum", - "repo": "copilot-cmp", - "type": "github" - } - }, - "nvim_plugin-zbirenbaum/copilot.lua": { - "flake": false, - "locked": { - "lastModified": 1766207702, - "narHash": "sha256-879050VUJpWBrHxUA3hRpcYbn3KgBGpVpKLdSVOwbIA=", - "owner": "zbirenbaum", - "repo": "copilot.lua", - "rev": "e78d1ffebdf6ccb6fd8be4e6898030c1cf5f9b64", - "type": "github" - }, - "original": { - "owner": "zbirenbaum", - "repo": "copilot.lua", - "type": "github" - } - }, "root": { "inputs": { "nixpkgs": "nixpkgs", "nvim_plugin-Almo7aya/openingh.nvim": "nvim_plugin-Almo7aya/openingh.nvim", - "nvim_plugin-CopilotC-Nvim/CopilotChat.nvim": "nvim_plugin-CopilotC-Nvim/CopilotChat.nvim", "nvim_plugin-JoosepAlviste/nvim-ts-context-commentstring": "nvim_plugin-JoosepAlviste/nvim-ts-context-commentstring", "nvim_plugin-L3MON4D3/LuaSnip": "nvim_plugin-L3MON4D3/LuaSnip", "nvim_plugin-MeanderingProgrammer/render-markdown.nvim": "nvim_plugin-MeanderingProgrammer/render-markdown.nvim", @@ -896,9 +879,13 @@ "nvim_plugin-catppuccin/nvim": "nvim_plugin-catppuccin/nvim", "nvim_plugin-chrisgrieser/nvim-early-retirement": "nvim_plugin-chrisgrieser/nvim-early-retirement", "nvim_plugin-declancm/cinnamon.nvim": "nvim_plugin-declancm/cinnamon.nvim", + "nvim_plugin-direnv/direnv.vim": "nvim_plugin-direnv/direnv.vim", + "nvim_plugin-echasnovski/mini.nvim": "nvim_plugin-echasnovski/mini.nvim", "nvim_plugin-folke/lazy.nvim": "nvim_plugin-folke/lazy.nvim", - "nvim_plugin-folke/neodev.nvim": "nvim_plugin-folke/neodev.nvim", + "nvim_plugin-folke/lazydev.nvim": "nvim_plugin-folke/lazydev.nvim", + "nvim_plugin-folke/trouble.nvim": "nvim_plugin-folke/trouble.nvim", "nvim_plugin-folke/which-key.nvim": "nvim_plugin-folke/which-key.nvim", + "nvim_plugin-ggml-org/llama.vim": "nvim_plugin-ggml-org/llama.vim", "nvim_plugin-hrsh7th/cmp-buffer": "nvim_plugin-hrsh7th/cmp-buffer", "nvim_plugin-hrsh7th/cmp-nvim-lsp": "nvim_plugin-hrsh7th/cmp-nvim-lsp", "nvim_plugin-hrsh7th/cmp-path": "nvim_plugin-hrsh7th/cmp-path", @@ -913,7 +900,6 @@ "nvim_plugin-mfussenegger/nvim-lint": "nvim_plugin-mfussenegger/nvim-lint", "nvim_plugin-mrcjkb/rustaceanvim": "nvim_plugin-mrcjkb/rustaceanvim", "nvim_plugin-neovim/nvim-lspconfig": "nvim_plugin-neovim/nvim-lspconfig", - "nvim_plugin-numToStr/Comment.nvim": "nvim_plugin-numToStr/Comment.nvim", "nvim_plugin-nvim-lua/plenary.nvim": "nvim_plugin-nvim-lua/plenary.nvim", "nvim_plugin-nvim-lualine/lualine.nvim": "nvim_plugin-nvim-lualine/lualine.nvim", "nvim_plugin-nvim-telescope/telescope-file-browser.nvim": "nvim_plugin-nvim-telescope/telescope-file-browser.nvim", @@ -932,11 +918,8 @@ "nvim_plugin-stevearc/conform.nvim": "nvim_plugin-stevearc/conform.nvim", "nvim_plugin-stevearc/dressing.nvim": "nvim_plugin-stevearc/dressing.nvim", "nvim_plugin-tpope/vim-sleuth": "nvim_plugin-tpope/vim-sleuth", - "nvim_plugin-tpope/vim-surround": "nvim_plugin-tpope/vim-surround", "nvim_plugin-uga-rosa/ccc.nvim": "nvim_plugin-uga-rosa/ccc.nvim", "nvim_plugin-windwp/nvim-ts-autotag": "nvim_plugin-windwp/nvim-ts-autotag", - "nvim_plugin-zbirenbaum/copilot-cmp": "nvim_plugin-zbirenbaum/copilot-cmp", - "nvim_plugin-zbirenbaum/copilot.lua": "nvim_plugin-zbirenbaum/copilot.lua", "rust-overlay": "rust-overlay" } }, @@ -947,11 +930,11 @@ ] }, "locked": { - "lastModified": 1766457837, - "narHash": "sha256-aeBbkQ0HPFNOIsUeEsXmZHXbYq4bG8ipT9JRlCcKHgU=", + "lastModified": 1769091129, + "narHash": "sha256-Jj/vIHjiu4OdDIrDXZ3xOPCJrMZZKzhE2UIVXV/NYzY=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "2c7510a559416d07242621d036847152d970612b", + "rev": "131e22d6a6d54ab72aeef6a5a661ab7005b4c596", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index f814af7..1a28e58 100644 --- a/flake.nix +++ b/flake.nix @@ -56,8 +56,6 @@ "nvim_plugin-JoosepAlviste/nvim-ts-context-commentstring".url = "github:JoosepAlviste/nvim-ts-context-commentstring"; "nvim_plugin-JoosepAlviste/nvim-ts-context-commentstring".flake = false; - "nvim_plugin-numToStr/Comment.nvim".url = "github:numToStr/Comment.nvim"; - "nvim_plugin-numToStr/Comment.nvim".flake = false; "nvim_plugin-windwp/nvim-ts-autotag".url = "github:windwp/nvim-ts-autotag"; "nvim_plugin-windwp/nvim-ts-autotag".flake = false; "nvim_plugin-uga-rosa/ccc.nvim".url = "github:uga-rosa/ccc.nvim"; @@ -78,8 +76,9 @@ "nvim_plugin-MeanderingProgrammer/render-markdown.nvim".flake = false; "nvim_plugin-Almo7aya/openingh.nvim".url = "github:Almo7aya/openingh.nvim"; "nvim_plugin-Almo7aya/openingh.nvim".flake = false; - "nvim_plugin-tpope/vim-surround".url = "github:tpope/vim-surround"; - "nvim_plugin-tpope/vim-surround".flake = false; + # mini.nvim replaces vim-surround, Comment.nvim + "nvim_plugin-echasnovski/mini.nvim".url = "github:echasnovski/mini.nvim"; + "nvim_plugin-echasnovski/mini.nvim".flake = false; "nvim_plugin-johmsalas/text-case.nvim".url = "github:johmsalas/text-case.nvim"; "nvim_plugin-johmsalas/text-case.nvim".flake = false; "nvim_plugin-mbbill/undotree".url = "github:mbbill/undotree"; @@ -96,10 +95,9 @@ "nvim_plugin-neovim/nvim-lspconfig".flake = false; "nvim_plugin-b0o/schemastore.nvim".url = "github:b0o/schemastore.nvim"; "nvim_plugin-b0o/schemastore.nvim".flake = false; + # Completion: nvim-cmp (blink.cmp had stability issues) "nvim_plugin-hrsh7th/nvim-cmp".url = "github:hrsh7th/nvim-cmp"; "nvim_plugin-hrsh7th/nvim-cmp".flake = false; - "nvim_plugin-L3MON4D3/LuaSnip".url = "github:L3MON4D3/LuaSnip"; - "nvim_plugin-L3MON4D3/LuaSnip".flake = false; "nvim_plugin-saadparwaiz1/cmp_luasnip".url = "github:saadparwaiz1/cmp_luasnip"; "nvim_plugin-saadparwaiz1/cmp_luasnip".flake = false; "nvim_plugin-hrsh7th/cmp-nvim-lsp".url = "github:hrsh7th/cmp-nvim-lsp"; @@ -108,16 +106,22 @@ "nvim_plugin-hrsh7th/cmp-path".flake = false; "nvim_plugin-hrsh7th/cmp-buffer".url = "github:hrsh7th/cmp-buffer"; "nvim_plugin-hrsh7th/cmp-buffer".flake = false; - "nvim_plugin-zbirenbaum/copilot-cmp".url = "github:zbirenbaum/copilot-cmp"; - "nvim_plugin-zbirenbaum/copilot-cmp".flake = false; - "nvim_plugin-zbirenbaum/copilot.lua".url = "github:zbirenbaum/copilot.lua"; - "nvim_plugin-zbirenbaum/copilot.lua".flake = false; - "nvim_plugin-CopilotC-Nvim/CopilotChat.nvim".url = "github:CopilotC-Nvim/CopilotChat.nvim"; - "nvim_plugin-CopilotC-Nvim/CopilotChat.nvim".flake = false; + "nvim_plugin-L3MON4D3/LuaSnip".url = "github:L3MON4D3/LuaSnip"; + "nvim_plugin-L3MON4D3/LuaSnip".flake = false; "nvim_plugin-stevearc/dressing.nvim".url = "github:stevearc/dressing.nvim"; "nvim_plugin-stevearc/dressing.nvim".flake = false; - "nvim_plugin-folke/neodev.nvim".url = "github:folke/neodev.nvim"; - "nvim_plugin-folke/neodev.nvim".flake = false; + # lazydev.nvim replaces neodev.nvim (which is archived) + "nvim_plugin-folke/lazydev.nvim".url = "github:folke/lazydev.nvim"; + "nvim_plugin-folke/lazydev.nvim".flake = false; + # trouble.nvim for better diagnostics UI + "nvim_plugin-folke/trouble.nvim".url = "github:folke/trouble.nvim"; + "nvim_plugin-folke/trouble.nvim".flake = false; + # direnv.vim for project environment integration + "nvim_plugin-direnv/direnv.vim".url = "github:direnv/direnv.vim"; + "nvim_plugin-direnv/direnv.vim".flake = false; + # llama.vim for local AI autocomplete + "nvim_plugin-ggml-org/llama.vim".url = "github:ggml-org/llama.vim"; + "nvim_plugin-ggml-org/llama.vim".flake = false; "nvim_plugin-mrcjkb/rustaceanvim".url = "github:mrcjkb/rustaceanvim"; "nvim_plugin-mrcjkb/rustaceanvim".flake = false; "nvim_plugin-Saecki/crates.nvim".url = "github:Saecki/crates.nvim"; @@ -196,6 +200,7 @@ glow curl sshfs + direnv # Auto-load project devShell environments # nix lang stuff nixfmt-rfc-style diff --git a/init.lua b/init.lua index a796a9c..c3b4c71 100644 --- a/init.lua +++ b/init.lua @@ -49,9 +49,9 @@ local function getSpec() local p = ensure_table(plugin) if U.isArray(p) and #p > 1 then local plugins = {} - table.foreachi(p, function(i, inner) + for _, inner in ipairs(p) do table.insert(plugins, convertPluginToNixStore(inner)) - end) + end return plugins end if p.enabled == false then @@ -77,11 +77,13 @@ local function getSpec() local plugins = {} local plugins_path = debug.getinfo(2, "S").source:sub(2):match("(.*/)") .. "lua/plugins" - for _, file in ipairs(vim.fn.readdir(plugins_path, [[v:val =~ '\.lua$']])) do - local plugin = string.sub(file, 0, -5) - local converted = convertPluginToNixStore(require("plugins." .. plugin)) - if converted ~= nil then - table.insert(plugins, converted) + for _, file in ipairs(vim.fn.readdir(plugins_path)) do + if file:match("%.lua$") then + local plugin = string.sub(file, 0, -5) + local converted = convertPluginToNixStore(require("plugins." .. plugin)) + if converted ~= nil then + table.insert(plugins, converted) + end end end return plugins diff --git a/lua/plugins/cmp_autocompletion.lua b/lua/plugins/cmp_autocompletion.lua deleted file mode 100644 index 109448c..0000000 --- a/lua/plugins/cmp_autocompletion.lua +++ /dev/null @@ -1,111 +0,0 @@ -return { - "hrsh7th/nvim-cmp", - event = "InsertEnter", - dependencies = { - -- Snippet Engine & its associated nvim-cmp source - { - "L3MON4D3/LuaSnip", - dependencies = { - { - "rafamadriz/friendly-snippets", - config = function() - require("luasnip.loaders.from_vscode").lazy_load() - end, - }, - }, - }, - "saadparwaiz1/cmp_luasnip", - "hrsh7th/cmp-nvim-lsp", - "hrsh7th/cmp-buffer", - "hrsh7th/cmp-path", - { - "zbirenbaum/copilot.lua", - cmd = "Copilot", - event = "InsertEnter", - opts = { - copilot_node_command = (NIX and NIX.nodejs_24_path and (NIX.nodejs_24_path .. "/bin/node")) or "node", - }, - main = "copilot", - }, - { "zbirenbaum/copilot-cmp", opts = {}, main = "copilot_cmp" }, - }, - config = function() - -- See `:help cmp` - 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({ - -- Scroll the documentation window [b]ack / [f]orward - [""] = cmp.mapping.scroll_docs(-4), - [""] = cmp.mapping.scroll_docs(4), - [""] = cmp.mapping.abort(), - [""] = cmp.mapping(function(fallback) - if cmp.visible() then - cmp.abort() - if cmp.get_active_entry() == nil then - -- TODO this is still being weird... if I go into active entry then back up and press esc it causes havoc - fallback() - end - else - fallback() - end - end), - -- [""] = cmp.mapping.abort(), - - -- Select the [n]ext item - [""] = 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" }), - -- Select the [p]revious item - [""] = 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" }), - [""] = cmp.mapping.confirm({ select = true }), - [""] = cmp.mapping.complete({}), - }), - sources = { - { - name = "copilot", - priority = 9, - -- keyword_length = 1, - -- filter = function(keyword) - -- -- Check if keyword length is some number and not just whitespace - -- if #keyword < 2 or keyword:match("^%s*$") then - -- return false - -- end - -- return true - -- end, - -- max_item_count = 3, - }, - { name = "nvim_lsp", priority = 8, max_item_count = 100 }, - { name = "luasnip", priority = 7, max_item_count = 5 }, - -- This source provides file path completions, helping you to complete file paths in your code - { name = "path", priority = 7, max_item_count = 3 }, - -- This source provides completion items from the current buffer, meaning it suggests words that have already been typed in the same file. - { name = "buffer", priority = 6, max_item_count = 5 }, - -- Rust crates.io integration - { name = "crates" }, - }, - }) - end, -} diff --git a/lua/plugins/comments_support.lua b/lua/plugins/comments_support.lua deleted file mode 100644 index 5ae22f2..0000000 --- a/lua/plugins/comments_support.lua +++ /dev/null @@ -1,45 +0,0 @@ -return { - "numToStr/Comment.nvim", - dependencies = { - { - -- This will auto change the commentstring option in files that could have varying - -- comment modes like in jsx/markdown/files with embedded languages - "JoosepAlviste/nvim-ts-context-commentstring", - init = function() - -- skip backwards compatibility routines and speed up loading - vim.g.skip_ts_context_commentstring_module = true - end, - config = function() - require("ts_context_commentstring").setup({}) - end, - }, - }, - config = function() - require("Comment").setup({ - pre_hook = function() - return vim.bo.commentstring - end, - mappings = { - basic = false, - extra = false, - }, - }) - vim.cmd("filetype plugin on") - end, - keys = { - { - "/", - "(comment_toggle_linewise_visual)", - 'lua require("Comment.api").locked("toggle.linewise")(vim.fn.visualmode())', - mode = { "x" }, - desc = "Toggle comments on selection", - }, - { - "/", - "V(comment_toggle_linewise_visual)", - 'lua require("Comment.api").locked("toggle.linewise")(vim.fn.visualmode())', - mode = { "n" }, - desc = "Toggle comments on line", - }, - }, -} diff --git a/lua/plugins/completion.lua b/lua/plugins/completion.lua new file mode 100644 index 0000000..2754fb3 --- /dev/null +++ b/lua/plugins/completion.lua @@ -0,0 +1,74 @@ +-- Completion engine using nvim-cmp +-- Keeping nvim-cmp for now due to blink.cmp stability issues +return { + { + "hrsh7th/nvim-cmp", + event = "InsertEnter", + dependencies = { + "L3MON4D3/LuaSnip", + "saadparwaiz1/cmp_luasnip", + "hrsh7th/cmp-nvim-lsp", + "hrsh7th/cmp-buffer", + "hrsh7th/cmp-path", + "rafamadriz/friendly-snippets", + }, + config = function() + local cmp = require("cmp") + local luasnip = require("luasnip") + + -- Load snippets + require("luasnip.loaders.from_vscode").lazy_load() + + 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.confirm({ select = true }), + [""] = cmp.mapping.complete(), + [""] = cmp.mapping.scroll_docs(-4), + [""] = cmp.mapping.scroll_docs(4), + [""] = cmp.mapping.abort(), + [""] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.abort() + end + fallback() -- Still exit insert mode after aborting + end, { "i", "s" }), + }), + sources = cmp.config.sources({ + { name = "nvim_lsp", priority = 8 }, + { name = "luasnip", priority = 7 }, + { name = "path", priority = 7 }, + { name = "buffer", priority = 6 }, + }), + window = { + completion = cmp.config.window.bordered(), + documentation = cmp.config.window.bordered(), + }, + }) + end, + }, + -- LuaSnip for snippet expansion + { + "L3MON4D3/LuaSnip", + lazy = true, + build = (function() + if vim.fn.has("win32") == 1 or vim.fn.executable("make") == 0 then + return + end + return "make install_jsregexp" + end)(), + opts = { + history = true, + delete_check_events = "TextChanged", + }, + }, +} diff --git a/lua/plugins/diagnostics.lua b/lua/plugins/diagnostics.lua new file mode 100644 index 0000000..cdef268 --- /dev/null +++ b/lua/plugins/diagnostics.lua @@ -0,0 +1,21 @@ +-- trouble.nvim - Pretty diagnostics, references, and quickfix lists +return { + "folke/trouble.nvim", + cmd = "Trouble", + opts = { + focus = false, + auto_preview = true, + modes = { + symbols = { + win = { position = "right", width = 40 }, + }, + }, + }, + keys = { + { "xx", "Trouble diagnostics toggle", desc = "Diagnostics (Trouble)" }, + { "xX", "Trouble diagnostics toggle filter.buf=0", desc = "Buffer Diagnostics (Trouble)" }, + { "xs", "Trouble symbols toggle focus=false", desc = "Symbols (Trouble)" }, + { "xq", "Trouble qflist toggle", desc = "Quickfix (Trouble)" }, + { "xl", "Trouble loclist toggle", desc = "Location List (Trouble)" }, + }, +} diff --git a/lua/plugins/direnv.lua b/lua/plugins/direnv.lua new file mode 100644 index 0000000..61ed56e --- /dev/null +++ b/lua/plugins/direnv.lua @@ -0,0 +1,7 @@ +-- direnv.vim - Auto-load project environment variables +-- This enables project devShells to provide LSPs and tools automatically +return { + "direnv/direnv.vim", + lazy = false, -- Must load early before LSP + priority = 90, +} diff --git a/lua/plugins/conform_formatter.lua b/lua/plugins/formatting.lua similarity index 100% rename from lua/plugins/conform_formatter.lua rename to lua/plugins/formatting.lua diff --git a/lua/plugins/lazydev.lua b/lua/plugins/lazydev.lua new file mode 100644 index 0000000..15f90ea --- /dev/null +++ b/lua/plugins/lazydev.lua @@ -0,0 +1,12 @@ +-- lazydev.nvim - Faster Lua/Neovim development +-- Replaces neodev.nvim (which is archived) +return { + "folke/lazydev.nvim", + ft = "lua", + opts = { + library = { + -- Load luv types when vim.uv is used + { path = "${3rd}/luv/library", words = { "vim%.uv" } }, + }, + }, +} diff --git a/lua/plugins/lint.lua b/lua/plugins/linting.lua similarity index 100% rename from lua/plugins/lint.lua rename to lua/plugins/linting.lua diff --git a/lua/plugins/llm_autocomplete.lua b/lua/plugins/llm_autocomplete.lua new file mode 100644 index 0000000..105a0d8 --- /dev/null +++ b/lua/plugins/llm_autocomplete.lua @@ -0,0 +1,61 @@ +-- Local AI autocomplete using llama.vim +-- Supports sweep-next-edit-1.5B and other FIM-capable models via llama-server +-- +-- Usage: +-- 1. Start llama-server with your model: +-- llama-server -m sweep-next-edit-Q8_0.gguf --port 8012 --fim-qwen-7b-default +-- 2. Neovim will auto-detect the server and enable completions +-- 3. Use Tab to accept, Shift-Tab for first line, Ctrl-F to toggle +-- 4. Toggle on/off with ,a + +-- Check if llama-server is running (sync, for cond check) +local function is_llama_server_running() + -- Quick sync check - only used at startup + local result = vim.system( + { "curl", "-s", "-o", "/dev/null", "-w", "%{http_code}", "--connect-timeout", "0.5", "http://127.0.0.1:8012/health" }, + { text = true } + ):wait() + return result.code == 0 and result.stdout and result.stdout:match("200") +end + +-- Cache the server status at load time +local server_available = nil + +return { + "ggml-org/llama.vim", + -- Only load if llama-server is running, or load lazily via command + cond = function() + if server_available == nil then + server_available = is_llama_server_running() + end + return server_available + end, + event = "InsertEnter", + init = function() + -- Default configuration + vim.g.llama_config = { + endpoint = "http://127.0.0.1:8012/infill", + auto_fim = true, -- Enable since we only load when server is available + show_info = 1, + -- Keymaps are handled by the plugin: + -- Tab - accept completion + -- Shift-Tab - accept first line only + -- Ctrl-F - toggle FIM manually + } + vim.notify("llama.vim: server detected, AI completions enabled", vim.log.levels.INFO) + end, + keys = { + { + ",a", + function() + -- Toggle auto_fim + if vim.g.llama_config then + vim.g.llama_config.auto_fim = not vim.g.llama_config.auto_fim + local status = vim.g.llama_config.auto_fim and "enabled" or "disabled" + vim.notify("llama.vim auto-complete " .. status, vim.log.levels.INFO) + end + end, + desc = "Toggle AI autocomplete (llama.vim)", + }, + }, +} diff --git a/lua/plugins/lsp.lua b/lua/plugins/lsp.lua index 6392ecb..a8f783a 100644 --- a/lua/plugins/lsp.lua +++ b/lua/plugins/lsp.lua @@ -11,12 +11,12 @@ vim.g.rustaceanvim = { return { -- LSP helper plugins for various languages - { "folke/neodev.nvim", event = { "BufRead *.lua", "BufRead *.vim" }, opts = {}, main = "neodev" }, + -- lazydev.nvim handles Lua/Neovim development (configured in lazydev.lua) -- { TODO come back to this, do I actually use any features provided here? I was losing out on rust-analyzer stuff when this was on and it was added below... -- "mrcjkb/rustaceanvim", -- -- uses ftplugins to enable itself lazily already -- lazy = false, - -- }, + -- } -- TODO add some hotkeys for opening the popup menus on crates { "Saecki/crates.nvim", event = "BufRead Cargo.toml", tag = "stable", opts = {}, main = "crates" }, { @@ -31,7 +31,6 @@ return { "neovim/nvim-lspconfig", event = "BufEnter", dependencies = { - { "hrsh7th/nvim-cmp" }, { "b0o/schemastore.nvim" }, -- Automatically install LSPs and related tools to stdpath for Neovim { "williamboman/mason.nvim", enabled = not NIX, config = true }, -- NOTE: Must be loaded before dependants @@ -71,6 +70,7 @@ return { }) local capabilities = vim.lsp.protocol.make_client_capabilities() + -- Extend capabilities with cmp-nvim-lsp for better completion support U.safeRequire("cmp_nvim_lsp", function(c) capabilities = vim.tbl_deep_extend("force", capabilities, c.default_capabilities()) end) @@ -96,26 +96,18 @@ return { completion = { callSnippet = "Replace", }, - workspace = { - checkThirdParty = false, - library = { - vim.env.VIMRUNTIME, - vim.api.nvim_get_runtime_file("", true), - vim.fn.expand("$VIMRUNTIME/lua"), - vim.fn.expand("$VIMRUNTIME/lua/vim/lsp"), - }, - telemetry = { enable = false }, - diagnostics = { - globals = { - "vim", - "require", - "NIX", - "U", - -- Hammerspoon for macos - "hs", - }, + -- lazydev.nvim handles workspace library configuration + diagnostics = { + globals = { + "vim", + "require", + "NIX", + "U", + -- Hammerspoon for macos + "hs", }, }, + telemetry = { enable = false }, }, }, }, @@ -214,6 +206,52 @@ return { pcall(vim.keymap.del, m.mode, m.lhs) end + -- Smart LSP detection: notify user when LSP is missing for a filetype + -- This helps guide users to add LSPs to their project devShell + local expected_lsp_for_filetype = { + rust = { name = "rust-analyzer", binary = "rust-analyzer" }, + typescript = { name = "ts_ls", binary = "typescript-language-server" }, + typescriptreact = { name = "ts_ls", binary = "typescript-language-server" }, + javascript = { name = "ts_ls", binary = "typescript-language-server" }, + javascriptreact = { name = "ts_ls", binary = "typescript-language-server" }, + python = { name = "pylsp", binary = "pylsp" }, + go = { name = "gopls", binary = "gopls" }, + svelte = { name = "svelte", binary = "svelteserver" }, + css = { name = "cssls", binary = "vscode-css-language-server" }, + html = { name = "html", binary = "vscode-html-language-server" }, + json = { name = "jsonls", binary = "vscode-json-language-server" }, + yaml = { name = "yamlls", binary = "yaml-language-server" }, + toml = { name = "taplo", binary = "taplo" }, + markdown = { name = "marksman", binary = "marksman" }, + xml = { name = "lemminx", binary = "lemminx" }, + -- lua and nix are always available from core deps + } + local lsp_warned = {} + vim.api.nvim_create_autocmd("FileType", { + group = vim.api.nvim_create_augroup("myconfig-lsp-detect", { clear = true }), + callback = function(args) + local ft = args.match + local expected = expected_lsp_for_filetype[ft] + if expected and not lsp_warned[ft] then + -- Check if the binary is available + if vim.fn.executable(expected.binary) ~= 1 then + lsp_warned[ft] = true + vim.defer_fn(function() + vim.notify( + string.format( + "LSP '%s' for %s not found.\nAdd '%s' to your project devShell.", + expected.name, + ft, + expected.binary + ), + vim.log.levels.WARN + ) + end, 500) + end + end + end, + }) + if NIX then local lsp_servers = vim.tbl_keys(servers or {}) for _, server_name in ipairs(lsp_servers) do diff --git a/lua/plugins/mini.lua b/lua/plugins/mini.lua new file mode 100644 index 0000000..6a7372e --- /dev/null +++ b/lua/plugins/mini.lua @@ -0,0 +1,63 @@ +-- mini.nvim - Collection of minimal, fast, and composable Lua modules +-- Replaces: vim-surround, Comment.nvim, nvim-ts-context-commentstring +return { + "echasnovski/mini.nvim", + event = "VeryLazy", + config = function() + -- Surround: Add/delete/replace surroundings (brackets, quotes, etc.) + -- Mappings: gsa (add), gsd (delete), gsr (replace), gsf (find), gsF (find_left) + require("mini.surround").setup({ + mappings = { + add = "gsa", -- Add surrounding in Normal and Visual modes + delete = "gsd", -- Delete surrounding + replace = "gsr", -- Replace surrounding + find = "gsf", -- Find surrounding (to the right) + find_left = "gsF", -- Find surrounding (to the left) + highlight = "gsh", -- Highlight surrounding + update_n_lines = "gsn", -- Update `n_lines` + }, + }) + + -- Comment: Smart commenting with treesitter support + -- gc{motion} in Normal, gc in Visual to toggle comments + require("mini.comment").setup({ + -- Hooks for custom comment handling (e.g., JSX/TSX) + options = { + custom_commentstring = function() + -- Use treesitter commentstring if available + return require("ts_context_commentstring").calculate_commentstring() or vim.bo.commentstring + end, + }, + }) + + -- Auto pairs: Automatically close brackets, quotes, etc. + require("mini.pairs").setup() + + -- Enhanced text objects: Better text objects for quotes, brackets, etc. + -- Adds: aq/iq (quotes), ab/ib (brackets), af/if (function), etc. + require("mini.ai").setup() + + -- Preserve / for comment toggle (matches old Comment.nvim binding) + vim.keymap.set("n", "/", function() + return require("mini.comment").operator() .. "_" + end, { expr = true, desc = "Toggle comment on line" }) + + vim.keymap.set("x", "/", function() + return require("mini.comment").operator() + end, { expr = true, desc = "Toggle comment on selection" }) + end, + dependencies = { + -- Keep ts-context-commentstring for JSX/TSX/embedded languages + { + "JoosepAlviste/nvim-ts-context-commentstring", + lazy = true, + init = function() + -- Skip backwards compatibility routines + vim.g.skip_ts_context_commentstring_module = true + end, + opts = { + enable_autocmd = false, -- mini.comment handles this + }, + }, + }, +} diff --git a/lua/plugins/surround.lua b/lua/plugins/surround.lua deleted file mode 100644 index b9e1e0c..0000000 --- a/lua/plugins/surround.lua +++ /dev/null @@ -1,4 +0,0 @@ -return { - "tpope/vim-surround", - event = "VeryLazy", -} diff --git a/lua/plugins/treesitter.lua b/lua/plugins/treesitter.lua index e1cfcea..4c2c6cc 100644 --- a/lua/plugins/treesitter.lua +++ b/lua/plugins/treesitter.lua @@ -1,6 +1,8 @@ return { "nvim-treesitter/nvim-treesitter", - dependencies = { "windwp/nvim-ts-autotag", "JoosepAlviste/nvim-ts-context-commentstring" }, + dependencies = { "windwp/nvim-ts-autotag" }, + lazy = false, -- nvim-treesitter does not support lazy-loading per docs + build = ":TSUpdate", init = function() U.cmd_executable("tree-sitter", { [false] = function() @@ -8,48 +10,70 @@ return { end, }) end, - event = "BufRead", - cmd = { - "TSBufDisable", - "TSBufEnable", - "TSBufToggle", - "TSDisable", - "TSEnable", - "TSToggle", - "TSInstall", - "TSInstallInfo", - "TSInstallSync", - "TSModuleInfo", - "TSUninstall", - "TSUpdate", - "TSUpdateSync", - }, - opts = function() - local nonNixOpts = {} + config = function() + -- New nvim-treesitter API (post-rewrite) + -- Setup is optional and only needed for non-default install directory + local ts = require("nvim-treesitter") + + -- In nix mode, parsers are provided by the nix store, no installation needed if not NIX then - nonNixOpts = { - ensure_installed = "all", - auto_install = true, - } + -- Install common parsers (async) + ts.install({ + "bash", + "c", + "css", + "dockerfile", + "go", + "html", + "javascript", + "json", + "lua", + "markdown", + "markdown_inline", + "nix", + "python", + "rust", + "svelte", + "toml", + "tsx", + "typescript", + "vim", + "vimdoc", + "yaml", + }) end - return U.assign({ - highlight = { - enable = true, - use_languagetree = true, - disable = function(lang, bufnr) - if lang == "sql" then - return true - end - return vim.api.nvim_buf_line_count(bufnr) > 4000 - end, - additional_vim_regex_highlighting = false, - }, - incremental_selection = { enable = true }, - indent = { enable = true }, - autotag = { enable = true }, - }, nonNixOpts) - end, - config = function(_, opts) - require("nvim-treesitter.configs").setup(opts) + + -- Enable treesitter highlighting for all filetypes + vim.api.nvim_create_autocmd("FileType", { + group = vim.api.nvim_create_augroup("myconfig-treesitter-highlight", { clear = true }), + callback = function(args) + local bufnr = args.buf + local ft = args.match + + -- Skip large files + if vim.api.nvim_buf_line_count(bufnr) > 4000 then + return + end + + -- Skip sql (often has issues) + if ft == "sql" then + return + end + + -- Enable treesitter highlighting + pcall(vim.treesitter.start, bufnr) + end, + }) + + -- Enable treesitter-based folding + vim.api.nvim_create_autocmd("FileType", { + group = vim.api.nvim_create_augroup("myconfig-treesitter-fold", { clear = true }), + callback = function(args) + local win = vim.api.nvim_get_current_win() + vim.wo[win][0].foldexpr = "v:lua.vim.treesitter.foldexpr()" + vim.wo[win][0].foldmethod = "expr" + vim.wo[win][0].foldenable = false -- Start with folds open + end, + }) end, } diff --git a/lua/plugins/whichkey.lua b/lua/plugins/whichkey.lua index d109b0e..8c1df11 100644 --- a/lua/plugins/whichkey.lua +++ b/lua/plugins/whichkey.lua @@ -22,6 +22,7 @@ return { { "l", group = "LSP" }, { "lf", group = "LSP Find" }, { "t", group = "Tabs" }, + { "x", group = "Trouble/Diagnostics" }, }, }, }, diff --git a/lua/tools/init.lua b/lua/tools/init.lua index 1573dac..210fc29 100644 --- a/lua/tools/init.lua +++ b/lua/tools/init.lua @@ -4,8 +4,8 @@ local function script_path() end -- Extract the directory name from the script path local directory_name = script_path():match(".*/(.*)/") -for _, file in ipairs(vim.fn.readdir(script_path(), [[v:val =~ '\.lua$']])) do - if file ~= "init.lua" then +for _, file in ipairs(vim.fn.readdir(script_path())) do + if file ~= "init.lua" and file:match("%.lua$") then local neighbor = string.sub(file, 0, -5) require(directory_name .. "." .. neighbor) end diff --git a/todo.md b/todo.md new file mode 100644 index 0000000..24e763e --- /dev/null +++ b/todo.md @@ -0,0 +1,535 @@ +# Neovim Configuration Modernization TODO + +## Overview + +This document tracks the modernization of the neovim configuration with focus on: +- Reducing nix flake bloat via direnv + project devShells +- Replacing nvim-cmp with faster blink.cmp +- Adding local AI autocomplete via llama.vim (for sweep-next-edit-1.5B) +- Consolidating plugins with mini.nvim +- Improving diagnostics UX with trouble.nvim +- Better Lua development with lazydev.nvim +- Restructuring LSP/lint/format modules + +--- + +## Phase 1: Nix Dependency Reduction + +### 1.1 Modify flake.nix +- [ ] Move most LSPs from `runtimeDependenciesFull` to project devShells +- [ ] Keep in core: `rg`, `fd`, `tree-sitter`, `fzf`, `glow`, `curl`, `sshfs`, `nixfmt`, `nil`, `stylua`, `lua-language-server` +- [ ] Add `direnv` to `runtimeDependenciesCore` +- [ ] Create a new tier: `runtimeDependenciesCommon` for commonly used formatters (prettier, stylua) that aren't LSPs + +### 1.2 Add new flake inputs for new plugins +- [ ] `nvim_plugin-saghen/blink.cmp` +- [ ] `nvim_plugin-folke/trouble.nvim` +- [ ] `nvim_plugin-echasnovski/mini.nvim` +- [ ] `nvim_plugin-folke/lazydev.nvim` +- [ ] `nvim_plugin-direnv/direnv.vim` +- [ ] `nvim_plugin-ggml-org/llama.vim` + +### 1.3 Remove deprecated/unused flake inputs +- [ ] `nvim_plugin-folke/neodev.nvim` (replaced by lazydev) +- [ ] `nvim_plugin-zbirenbaum/copilot.lua` (removing copilot) +- [ ] `nvim_plugin-zbirenbaum/copilot-cmp` (removing copilot) +- [ ] `nvim_plugin-CopilotC-Nvim/CopilotChat.nvim` (removing copilot) +- [ ] `nvim_plugin-hrsh7th/nvim-cmp` (replaced by blink.cmp) +- [ ] `nvim_plugin-saadparwaiz1/cmp_luasnip` (nvim-cmp dependency) +- [ ] `nvim_plugin-hrsh7th/cmp-nvim-lsp` (nvim-cmp dependency) +- [ ] `nvim_plugin-hrsh7th/cmp-path` (nvim-cmp dependency) +- [ ] `nvim_plugin-hrsh7th/cmp-buffer` (nvim-cmp dependency) +- [ ] `nvim_plugin-numToStr/Comment.nvim` (replaced by mini.comment) +- [ ] `nvim_plugin-JoosepAlviste/nvim-ts-context-commentstring` (Comment.nvim dep, mini.comment uses native treesitter) +- [ ] `nvim_plugin-tpope/vim-surround` (replaced by mini.surround) + +--- + +## Phase 2: Replace nvim-cmp with blink.cmp + +### 2.1 Create new completion config +- [ ] Create `lua/plugins/completion.lua` with blink.cmp setup +- [ ] Configure keymaps: ``/`` select, `` accept, ``/`` scroll docs +- [ ] Enable ghost text preview +- [ ] Enable signature help +- [ ] Configure sources: lsp, path, snippets, buffer + +### 2.2 Remove old completion config +- [ ] Delete `lua/plugins/cmp_autocompletion.lua` +- [ ] Keep `L3MON4D3/LuaSnip` and `rafamadriz/friendly-snippets` for snippet support + +### 2.3 Update LSP config +- [ ] Remove `cmp_nvim_lsp.default_capabilities()` call (blink.cmp handles this differently) +- [ ] Update capabilities setup for blink.cmp compatibility + +--- + +## Phase 3: Local AI Autocomplete (llama.vim) + +### 3.1 Create llama.vim config +- [ ] Create `lua/plugins/llm_autocomplete.lua` +- [ ] Auto-detect if llama-server is running on startup (check endpoint) +- [ ] Configure for FIM (fill-in-middle) completion +- [ ] Default endpoint: `http://127.0.0.1:8012/infill` +- [ ] Add toggle keymap `,a` to enable/disable + +### 3.2 Document llama-server setup +- [ ] Add README section for running llama-server with sweep-next-edit-1.5B +- [ ] Example command: `llama-server -m sweep-next-edit-Q8_0.gguf --port 8012 --fim-qwen-7b-default` + +### 3.3 Remove copilot +- [ ] Delete copilot references from `lua/plugins/cmp_autocompletion.lua` (will be deleted anyway) +- [ ] Ensure no other files reference copilot + +--- + +## Phase 4: Add direnv.vim + +### 4.1 Create direnv config +- [ ] Create `lua/plugins/direnv.lua` +- [ ] Load early (priority 90) to set up env before LSP starts +- [ ] Consider: auto-allow for trusted directories? + +--- + +## Phase 5: Smart LSP Detection & Warnings + +### 5.1 Create detection utility +- [ ] Add to `lua/util.lua` or create `lua/lsp_detect.lua`: + - Function to check if expected LSP is available for filetype + - Mapping of filetypes to expected LSP binaries + - Notification helper for missing LSPs + +### 5.2 Integrate into LSP config +- [ ] Add `FileType` autocmd that checks for expected LSP +- [ ] Show notification if LSP missing: "LSP '{name}' for {ft} not found. Add to project devShell." +- [ ] Debounce notifications (don't spam on startup) +- [ ] Option to disable warnings per-filetype or globally + +### Expected LSP mapping: +```lua +local expected_lsp = { + rust = "rust-analyzer", + typescript = "typescript-language-server", + typescriptreact = "typescript-language-server", + javascript = "typescript-language-server", + javascriptreact = "typescript-language-server", + python = "pylsp", + go = "gopls", + svelte = "svelteserver", + css = "vscode-css-language-server", + html = "vscode-html-language-server", + json = "vscode-json-language-server", + yaml = "yaml-language-server", + toml = "taplo", + markdown = "marksman", + xml = "lemminx", + -- lua and nix handled by core dependencies +} +``` + +--- + +## Phase 6: Add trouble.nvim for Diagnostics + +### 6.1 Create trouble.nvim config +- [ ] Create `lua/plugins/diagnostics.lua` +- [ ] Configure modes: diagnostics, symbols, quickfix +- [ ] Keymaps under `x`: + - `xx` - Toggle diagnostics + - `xX` - Buffer diagnostics only + - `xs` - Document symbols sidebar + - `xq` - Quickfix list + +### 6.2 Update which-key +- [ ] Add `x` group: "Trouble/Diagnostics" + +### 6.3 Optional: Telescope integration +- [ ] Add `` in telescope to send results to trouble + +--- + +## Phase 7: Add lazydev.nvim + +### 7.1 Create lazydev config +- [ ] Create `lua/plugins/lazydev.lua` +- [ ] Configure for lua filetype +- [ ] Add luv library annotation + +### 7.2 Update LSP config +- [ ] Remove manual `lua_ls` workspace library configuration +- [ ] Remove neodev.nvim dependency from lsp.lua +- [ ] Let lazydev handle Neovim API completions + +--- + +## Phase 8: mini.nvim Consolidation + +### 8.1 Create mini.nvim config +- [ ] Create `lua/plugins/mini.lua` +- [ ] Configure modules: + - `mini.surround` - replaces vim-surround (mappings: `gsa`/`gsd`/`gsr`) + - `mini.comment` - replaces Comment.nvim (mappings: `gc`/`gcc`) + - `mini.pairs` - auto pairs (optional, consider if wanted) + - `mini.ai` - enhanced text objects + +### 8.2 Handle comment keybindings +- [ ] Current: `/` for toggle comment +- [ ] Preserve this mapping in mini.comment config or via custom keymap + +### 8.3 Remove replaced plugins +- [ ] Delete `lua/plugins/surround.lua` +- [ ] Delete `lua/plugins/comments_support.lua` + +--- + +## Phase 9: File Restructuring + +### 9.1 Rename files for consistency +- [ ] `conform_formatter.lua` -> `formatting.lua` +- [ ] `lint.lua` -> `linting.lua` + +### 9.2 Consider LSP module restructure (optional) +Current `lsp.lua` is large. Could split into: +``` +lua/plugins/lsp/ +├── init.lua # Main setup, keymaps +├── servers.lua # Server-specific configs +└── detect.lua # Smart detection logic +``` +Decision: Keep as single file unless it becomes unwieldy after changes. + +--- + +## Phase 10: Cleanup & Testing + +### 10.1 Test nix mode +- [ ] Run `nix run .` and verify all plugins load +- [ ] Check LSP works for lua and nix (core deps) +- [ ] Verify warning appears for other filetypes without LSP + +### 10.2 Test non-nix mode +- [ ] Clone fresh, run `nvim --headless "+Lazy! sync" +qa` +- [ ] Verify lazy.nvim fetches all plugins + +### 10.3 Verify lazy loading +- [ ] Check startup time with `:Lazy profile` +- [ ] Ensure plugins are still lazy loaded appropriately + +### 10.4 Update README +- [ ] Update "Without Nix" section +- [ ] Add section on direnv/devShell integration +- [ ] Add section on llama.vim / local AI setup +- [ ] Remove copilot mentions +- [ ] Update requirements (Neovim version, etc.) + +--- + +## Files Summary + +### Create +| File | Description | +|------|-------------| +| `lua/plugins/completion.lua` | blink.cmp configuration | +| `lua/plugins/llm_autocomplete.lua` | llama.vim for local AI | +| `lua/plugins/direnv.lua` | direnv.vim configuration | +| `lua/plugins/diagnostics.lua` | trouble.nvim configuration | +| `lua/plugins/lazydev.lua` | lazydev.nvim configuration | +| `lua/plugins/mini.lua` | mini.nvim modules | + +### Modify +| File | Changes | +|------|---------| +| `flake.nix` | Add/remove inputs, adjust dependencies | +| `lua/plugins/lsp.lua` | Add detection, remove neodev, update capabilities | +| `lua/plugins/whichkey.lua` | Add trouble group | +| `README.md` | Update documentation | + +### Delete +| File | Reason | +|------|--------| +| `lua/plugins/cmp_autocompletion.lua` | Replaced by blink.cmp | +| `lua/plugins/surround.lua` | Replaced by mini.surround | +| `lua/plugins/comments_support.lua` | Replaced by mini.comment | + +### Rename +| From | To | +|------|-----| +| `lua/plugins/conform_formatter.lua` | `lua/plugins/formatting.lua` | +| `lua/plugins/lint.lua` | `lua/plugins/linting.lua` | + +--- + +## Sub-Agent Task Prompts + +These tasks can be executed in parallel by sub-agents. Each prompt is self-contained. + +### Parallel Group A: New Plugin Configs (No Dependencies) + +#### Task A1: Create blink.cmp config +``` +Create lua/plugins/completion.lua for blink.cmp completion engine. + +Requirements: +- Use saghen/blink.cmp with version = "1.*" +- Event: InsertEnter +- Dependencies: rafamadriz/friendly-snippets, L3MON4D3/LuaSnip +- Keymaps: + - = select_next + - = select_prev + - = accept + - = scroll_documentation_up + - = scroll_documentation_down +- Sources: lsp, path, snippets, buffer +- Enable: ghost_text, documentation auto_show, signature help +- Follow lazy.nvim plugin spec format +``` + +#### Task A2: Create llama.vim config +``` +Create lua/plugins/llm_autocomplete.lua for local AI completion. + +Requirements: +- Use ggml-org/llama.vim +- Event: InsertEnter +- Auto-detect if llama-server is running: + - On VimEnter, async check if http://127.0.0.1:8012 responds + - Set vim.g.llama_enabled based on result +- vim.g.llama_config: + - endpoint = "http://127.0.0.1:8012/infill" + - auto_fim = true (only when enabled) + - show_info = 1 +- Add keymap ,a to toggle vim.g.llama_enabled with notification +- Follow lazy.nvim plugin spec format +``` + +#### Task A3: Create direnv.vim config +``` +Create lua/plugins/direnv.lua for project environment loading. + +Requirements: +- Use direnv/direnv.vim +- lazy = false (must load early) +- priority = 90 +- Simple config, direnv handles most things automatically +- Follow lazy.nvim plugin spec format +``` + +#### Task A4: Create trouble.nvim config +``` +Create lua/plugins/diagnostics.lua for better diagnostics UI. + +Requirements: +- Use folke/trouble.nvim +- cmd = "Trouble" (lazy load on command) +- opts: + - focus = false + - auto_preview = true + - modes.symbols.win = { position = "right", width = 40 } +- Keymaps: + - xx = Trouble diagnostics toggle + - xX = Trouble diagnostics toggle filter.buf=0 + - xs = Trouble symbols toggle focus=false + - xq = Trouble qflist toggle +- Follow lazy.nvim plugin spec format +``` + +#### Task A5: Create lazydev.nvim config +``` +Create lua/plugins/lazydev.lua for Lua/Neovim development. + +Requirements: +- Use folke/lazydev.nvim +- ft = "lua" +- opts.library = { { path = "${3rd}/luv/library", words = { "vim%.uv" } } } +- Follow lazy.nvim plugin spec format +``` + +#### Task A6: Create mini.nvim config +``` +Create lua/plugins/mini.lua to consolidate utility plugins. + +Requirements: +- Use echasnovski/mini.nvim +- event = VeryLazy +- In config function, setup these modules: + 1. mini.surround with mappings: gsa (add), gsd (delete), gsr (replace), gsf (find), gsF (find_left), gsh (highlight), gsn (update_n_lines) + 2. mini.comment (default config) + 3. mini.pairs (default config) + 4. mini.ai (default config for enhanced text objects) +- Add custom keymap to preserve / for comment toggle: + - Normal mode: toggle line comment + - Visual mode: toggle selection comment +- Follow lazy.nvim plugin spec format +``` + +### Parallel Group B: Flake Modifications + +#### Task B1: Update flake.nix inputs +``` +Modify flake.nix to add new plugin inputs and remove deprecated ones. + +ADD these inputs (follow existing pattern with .url and .flake = false): +- "nvim_plugin-saghen/blink.cmp" +- "nvim_plugin-folke/trouble.nvim" +- "nvim_plugin-echasnovski/mini.nvim" +- "nvim_plugin-folke/lazydev.nvim" +- "nvim_plugin-direnv/direnv.vim" +- "nvim_plugin-ggml-org/llama.vim" + +REMOVE these inputs: +- "nvim_plugin-folke/neodev.nvim" +- "nvim_plugin-zbirenbaum/copilot.lua" +- "nvim_plugin-zbirenbaum/copilot-cmp" +- "nvim_plugin-CopilotC-Nvim/CopilotChat.nvim" +- "nvim_plugin-hrsh7th/nvim-cmp" +- "nvim_plugin-saadparwaiz1/cmp_luasnip" +- "nvim_plugin-hrsh7th/cmp-nvim-lsp" +- "nvim_plugin-hrsh7th/cmp-path" +- "nvim_plugin-hrsh7th/cmp-buffer" +- "nvim_plugin-numToStr/Comment.nvim" +- "nvim_plugin-JoosepAlviste/nvim-ts-context-commentstring" +- "nvim_plugin-tpope/vim-surround" +``` + +#### Task B2: Restructure flake.nix dependencies +``` +Modify flake.nix runtimeDependencies to reduce bloat. + +KEEP in runtimeDependenciesCore (add direnv): +- ripgrep, fd, tree-sitter, fzf, glow, curl, sshfs +- nixfmt-rfc-style, nil +- Add: direnv + +CREATE new runtimeDependenciesCommon (formatters/linters often needed): +- stylua +- lua-language-server +- nodePackages.prettier +- markdownlint-cli +- markdownlint-cli2 + +REDUCE runtimeDependenciesFull to only LSPs/tools that are truly "full": +- biome, svelte-check, rustywind, sql-formatter, qmlformat deps +- All LSPs: vscode-langservers-extracted, typescript-language-server, svelte-language-server, tailwindcss-language-server, eslint_d, python-lsp-server, rust-analyzer, marksman, taplo, yaml-language-server, lemminx, gopls +- typescript, nodejs_24, clang, rust toolchain + +Update createNeovim to use: +- Core always via --suffix +- Common always via --suffix (after core) +- Full only when full=true via --suffix (last) +``` + +### Sequential Group C: LSP Config Updates (After Group A) + +#### Task C1: Update lsp.lua +``` +Modify lua/plugins/lsp.lua with the following changes: + +1. Remove neodev.nvim dependency - delete from dependencies list + +2. Update capabilities for blink.cmp: + - Remove: require('cmp_nvim_lsp').default_capabilities() + - Keep: vim.lsp.protocol.make_client_capabilities() + - Note: blink.cmp auto-registers its capabilities + +3. Simplify lua_ls config: + - Remove manual workspace.library settings (lazydev handles this) + - Keep: settings.Lua.diagnostics.globals = { "vim", "NIX", "U", "hs" } + +4. Add smart LSP detection (in the config function): + - Create expected_lsp table mapping filetypes to binary names + - Add FileType autocmd that checks vim.fn.executable + - Show vim.notify warning if LSP not found (debounced, 500ms delay) + - Warning message: "LSP '{name}' for {ft} not found. Add to project devShell." +``` + +### Sequential Group D: Cleanup (After Groups A, B, C) + +#### Task D1: Delete replaced plugin files +``` +Delete the following files that are replaced by mini.nvim: +- lua/plugins/surround.lua +- lua/plugins/comments_support.lua +- lua/plugins/cmp_autocompletion.lua +``` + +#### Task D2: Rename files for consistency +``` +Rename: +- lua/plugins/conform_formatter.lua -> lua/plugins/formatting.lua +- lua/plugins/lint.lua -> lua/plugins/linting.lua +``` + +#### Task D3: Update which-key config +``` +Modify lua/plugins/whichkey.lua: +- Add group for trouble: { "x", group = "Trouble/Diagnostics" } +- Add group for llm toggle if not exists: under , group +``` + +### Sequential Group E: Documentation (After All) + +#### Task E1: Update README.md +``` +Update README.md with: + +1. Update requirements section: + - Neovim >= 0.11 (for native LSP config) + - Note about direnv for project LSP support + +2. Add "Project LSP Setup" section: + - Explain that most LSPs come from project devShells via direnv + - Example flake.nix devShell with LSPs + - Note about core LSPs always available (lua, nix) + +3. Add "Local AI Completion" section: + - Explain llama.vim integration + - How to run llama-server with sweep-next-edit-1.5B + - Toggle with ,a + - Note: auto-detects if server running + +4. Remove: + - Copilot mentions + - Any outdated plugin references + +5. Update NOTES/TODOS section: + - Remove completed items + - Add any new future ideas +``` + +--- + +## Dependency Graph + +``` +Group A (Parallel - No deps) Group B (Parallel - No deps) +├── A1: completion.lua ├── B1: flake inputs +├── A2: llm_autocomplete.lua └── B2: flake deps +├── A3: direnv.lua +├── A4: diagnostics.lua +├── A5: lazydev.lua +└── A6: mini.lua + │ │ + └────────────┬───────────────────┘ + ▼ + Group C (Sequential) + └── C1: Update lsp.lua + │ + ▼ + Group D (Sequential) + ├── D1: Delete old files + ├── D2: Rename files + └── D3: Update which-key + │ + ▼ + Group E (Sequential) + └── E1: Update README +``` + +## Execution Order + +1. **Run in parallel**: A1, A2, A3, A4, A5, A6, B1, B2 +2. **After step 1**: C1 +3. **After step 2**: D1, D2, D3 (can be parallel) +4. **After step 3**: E1 +5. **Manual testing**: Verify nix and non-nix modes work