Refactor plugin layout, add AI autocomplete and direnv, update docs

This commit is contained in:
RingOfStorms (Joshua Bell) 2026-01-22 16:54:45 -06:00
parent 3517caecde
commit cc9a5dc0f5
20 changed files with 1195 additions and 414 deletions

153
README.md
View file

@ -2,10 +2,10 @@
Goals: 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 - LSP integration with the current project's settings if available
- Lean and fast startup with lazy loading
Old pre nix config: https://git.joshuabell.xyz/nvim/~files/40eadc9b714fa29c5b28aca49f77c1ea62141763 for reference - Project-driven tooling via direnv and devShells
## Running ## Running
@ -30,11 +30,9 @@ environment.systemPackages = with pkgs; [
### Without Nix ### Without Nix
TODO update this section
- Must have all required programs installed and available on path - Must have all required programs installed and available on path
- neovim >= 0.5 - neovim >= 0.11 (required for native LSP config)
- Evertying listed in flake.nix `runtime dependencies` variable near the top of the file - Everything listed in flake.nix `runtimeDependenciesCore` variable
- These must be available on the path - These must be available on the path
- Treesitter/Lazy/Mason will install all other requirements needed on other systems - 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 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
- **`<leader>,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
- `<leader>la` - Code action
- `<leader>lr` - Rename
### Diagnostics (Trouble)
- `<leader>xx` - Toggle diagnostics
- `<leader>xX` - Buffer diagnostics only
- `<leader>xs` - Document symbols
- `<leader>xq` - Quickfix list
### Comments (mini.comment)
- `gc{motion}` - Toggle comment
- `gcc` - Toggle line comment
- `<leader>/` - Toggle comment (preserved binding)
### Surround (mini.surround)
- `gsa{motion}{char}` - Add surrounding
- `gsd{char}` - Delete surrounding
- `gsr{old}{new}` - Replace surrounding
## NOTES/TODOS ## NOTES/TODOS
- See what linters/formaters to add or are the LSP's enough?
- CSPELL/spelling linter - CSPELL/spelling linter
- Consider mini-align for alignment
FUTURE FUTURE
- Make a new HTTP plugin for running curl commands from .http files - 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 - similar to rest-nvim/rest.nvim but support streaming etc and show command output
- Execute selected command and open output into a buffer/popup window? <leader>cx
- generate command, like scratch open a popup of things that can be generated. UUID/other stuff? - generate command, like scratch open a popup of things that can be generated. UUID/other stuff?
- <https://gilt hub.com/mawkler/nvim/blob/06cde9dbaedab2bb36c06025c07589c93d2c6d6b/lua/configs/luasnip.lua#L37-L50>
- Checkout cargo-bloat, cargo-cache, cargo-outdated - memcache sccache - Checkout cargo-bloat, cargo-cache, cargo-outdated - memcache sccache
- For scratches, just make an input box for custom extension rather than predefined list - For scratches, just make an input box for custom extension rather than predefined list
- freaking learn to use surround more often <https://github.com/tpope/vim-surround/tree/master>
- make my own session saving impl
- Only save visible buffers/tabs/splits
- per branch per directory
- something like <https://github.com/gennaro-tedesco/nvim-possession/tree/main> but fully managed
- copilot? local llm?
- check out - check out
- <https://github.com/onsails/lspkind.nvim>
- <https://github.com/echasnovski/mini.nvim/blob/main/readmes/mini-align.md>
- <https://github.com/tpope/vim-abolish> - <https://github.com/tpope/vim-abolish>

281
flake.lock generated
View file

@ -2,11 +2,11 @@
"nodes": { "nodes": {
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1766309749, "lastModified": 1769018530,
"narHash": "sha256-3xY8CZ4rSnQ0NqGhMKAy5vgC+2IVK0NoVEzDoOh4DA4=", "narHash": "sha256-MJ27Cy2NtBEV5tsK+YraYr2g851f3Fl1LpNHDzDX15c=",
"owner": "nixos", "owner": "nixos",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "a6531044f6d0bef691ea18d4d4ce44d0daa6e816", "rev": "88d3861acdd3d2f0e361767018218e51810df8a1",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -32,22 +32,6 @@
"type": "github" "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": { "nvim_plugin-JoosepAlviste/nvim-ts-context-commentstring": {
"flake": false, "flake": false,
"locked": { "locked": {
@ -67,11 +51,11 @@
"nvim_plugin-L3MON4D3/LuaSnip": { "nvim_plugin-L3MON4D3/LuaSnip": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1762213057, "lastModified": 1768781124,
"narHash": "sha256-Pil9m8zN3XzMtPT8spdr78dzkMW7dcpVnbWzie6524A=", "narHash": "sha256-3beTsZPT2EwzAVhEzqNhFRnDAU7C7GlzFFymY3aNp9M=",
"owner": "L3MON4D3", "owner": "L3MON4D3",
"repo": "LuaSnip", "repo": "LuaSnip",
"rev": "3732756842a2f7e0e76a7b0487e9692072857277", "rev": "dae4f5aaa3574bd0c2b9dd20fb9542a02c10471c",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -83,11 +67,11 @@
"nvim_plugin-MeanderingProgrammer/render-markdown.nvim": { "nvim_plugin-MeanderingProgrammer/render-markdown.nvim": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1765914395, "lastModified": 1768589366,
"narHash": "sha256-A7pm8sBQWsZl3Kc7JBh3gBUyKb6GfJ5J0zfn3mSGjKs=", "narHash": "sha256-kKvIivCNe6HlGqiChySeqEHRB0rj6ipKwjko4ix4tRw=",
"owner": "MeanderingProgrammer", "owner": "MeanderingProgrammer",
"repo": "render-markdown.nvim", "repo": "render-markdown.nvim",
"rev": "07d088bf8bdadd159eb807b90eaee86a4778383f", "rev": "c54380dd4d8d1738b9691a7c349ecad7967ac12e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -163,11 +147,11 @@
"nvim_plugin-b0o/schemastore.nvim": { "nvim_plugin-b0o/schemastore.nvim": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1766167236, "lastModified": 1768946435,
"narHash": "sha256-+Z1foMyKMxyMmYqmyu1KWiyL4Fc0Zm2SYV7RoZ9Ut2I=", "narHash": "sha256-nv8ZAqrQBe0ckmHqeI4HLLOKphwxjq7v3OAShQ7HtcY=",
"owner": "b0o", "owner": "b0o",
"repo": "schemastore.nvim", "repo": "schemastore.nvim",
"rev": "8b92ea89835b8e5dbc779a675ebb0e5fcb9a1993", "rev": "a0375eb6f7f944723162ef41c200ac6b364f53ac",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -179,11 +163,11 @@
"nvim_plugin-catppuccin/nvim": { "nvim_plugin-catppuccin/nvim": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1765701669, "lastModified": 1767886506,
"narHash": "sha256-8GKpGGdeBwxuMrheojyl162CzUntRcq9AktQVmKbpuI=", "narHash": "sha256-cZ6VeF69s0eQ9I7Tz8MoEKuF9w+TbA94vXj2EuDoSgU=",
"owner": "catppuccin", "owner": "catppuccin",
"repo": "nvim", "repo": "nvim",
"rev": "ce8d176faa4643e026e597ae3c31db59b63cef09", "rev": "beaf41a30c26fd7d6c386d383155cbd65dd554cd",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -195,11 +179,11 @@
"nvim_plugin-chrisgrieser/nvim-early-retirement": { "nvim_plugin-chrisgrieser/nvim-early-retirement": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1766186911, "lastModified": 1767720082,
"narHash": "sha256-COYpFOZTMGpZVfSJFMix/6TM5Eeemngcx1iukMa2nDE=", "narHash": "sha256-2fQsVQUAuKX0uz+umM7VCUFPRKmIr7L9KQIgnlo3bG0=",
"owner": "chrisgrieser", "owner": "chrisgrieser",
"repo": "nvim-early-retirement", "repo": "nvim-early-retirement",
"rev": "86edd80026e4eea2cef7d1e5dadcf34432e6098d", "rev": "79ea1568df53986e0d9f4d36fd542933a34b2e61",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -224,6 +208,38 @@
"type": "github" "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": { "nvim_plugin-folke/lazy.nvim": {
"flake": false, "flake": false,
"locked": { "locked": {
@ -240,19 +256,35 @@
"type": "github" "type": "github"
} }
}, },
"nvim_plugin-folke/neodev.nvim": { "nvim_plugin-folke/lazydev.nvim": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1720260306, "lastModified": 1762423570,
"narHash": "sha256-hOjzlo/IqmV8tYjGwfmcCPEmHYsWnEIwtHZdhpwA1kM=", "narHash": "sha256-1g1PLFR3bc++NimbrRpoOMZyqYWHeX6pDoxsiuoJHus=",
"owner": "folke", "owner": "folke",
"repo": "neodev.nvim", "repo": "lazydev.nvim",
"rev": "46aa467dca16cf3dfe27098042402066d2ae242d", "rev": "5231c62aa83c2f8dc8e7ba957aa77098cda1257d",
"type": "github" "type": "github"
}, },
"original": { "original": {
"owner": "folke", "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" "type": "github"
} }
}, },
@ -272,6 +304,22 @@
"type": "github" "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": { "nvim_plugin-hrsh7th/cmp-buffer": {
"flake": false, "flake": false,
"locked": { "locked": {
@ -323,11 +371,11 @@
"nvim_plugin-hrsh7th/nvim-cmp": { "nvim_plugin-hrsh7th/nvim-cmp": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1763258674, "lastModified": 1767368202,
"narHash": "sha256-Z6F8auKq1jSgGoPhV4RbkB1YTexnolSbEjpa/JJI/Fc=", "narHash": "sha256-gwuiUgz3UEFpaKs79BSWS4qkwOi+XMHIDFdYRatWt0g=",
"owner": "hrsh7th", "owner": "hrsh7th",
"repo": "nvim-cmp", "repo": "nvim-cmp",
"rev": "d97d85e01339f01b842e6ec1502f639b080cb0fc", "rev": "85bbfad83f804f11688d1ab9486b459e699292d6",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -339,11 +387,11 @@
"nvim_plugin-j-hui/fidget.nvim": { "nvim_plugin-j-hui/fidget.nvim": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1766143069, "lastModified": 1768329414,
"narHash": "sha256-uy2Z6vn9UYDN7Dr7iuiTrualRQdmUT0dwHP/eZXA/uA=", "narHash": "sha256-Zap4UVicIvCaPqCMgdlnEAGbMzq1xM4uGpVqZL1iju0=",
"owner": "j-hui", "owner": "j-hui",
"repo": "fidget.nvim", "repo": "fidget.nvim",
"rev": "64463022a1f2ff1318ab22a2ea4125ed9313a483", "rev": "7fa433a83118a70fe24c1ce88d5f0bd3453c0970",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -371,11 +419,11 @@
"nvim_plugin-lewis6991/gitsigns.nvim": { "nvim_plugin-lewis6991/gitsigns.nvim": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1764322768, "lastModified": 1768948049,
"narHash": "sha256-w3Q7nMFEbcjP6RmSTONg2Nw1dBXDEHnjQ69FuAPJRD8=", "narHash": "sha256-J9BvYVydeeoBj5Op+jGcI+i3IppdpoZ9jHbod0X1JFo=",
"owner": "lewis6991", "owner": "lewis6991",
"repo": "gitsigns.nvim", "repo": "gitsigns.nvim",
"rev": "5813e4878748805f1518cee7abb50fd7205a3a48", "rev": "abf82a65f185bd54adc0679f74b7d6e1ada690c9",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -435,11 +483,11 @@
"nvim_plugin-mbbill/undotree": { "nvim_plugin-mbbill/undotree": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1759186837, "lastModified": 1766990053,
"narHash": "sha256-EWOH08KAWyoT9m45/B1d5aKQQJtd3k4orJbagVsxe08=", "narHash": "sha256-5/SQjSjQPYIK55P2rNrgn9psOSNpWpqJzkpWmjo8Itg=",
"owner": "mbbill", "owner": "mbbill",
"repo": "undotree", "repo": "undotree",
"rev": "0f1c9816975b5d7f87d5003a19c53c6fd2ff6f7f", "rev": "178d19e00a643f825ea11d581b1684745d0c4eda",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -451,11 +499,11 @@
"nvim_plugin-mfussenegger/nvim-lint": { "nvim_plugin-mfussenegger/nvim-lint": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1766127989, "lastModified": 1767793421,
"narHash": "sha256-ysIoJ8uMAHu/OCemQ3yUYMhKIVnSDLQCvJH0SaGIOK4=", "narHash": "sha256-Ru+QklYFuwoeRvKlBXZcItuGvKDPbEq04sACKvTQds8=",
"owner": "mfussenegger", "owner": "mfussenegger",
"repo": "nvim-lint", "repo": "nvim-lint",
"rev": "7a64f4067065c16a355d40d0d599b8ca6b25de6d", "rev": "ca6ea12daf0a4d92dc24c5c9ae22a1f0418ade37",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -467,11 +515,11 @@
"nvim_plugin-mrcjkb/rustaceanvim": { "nvim_plugin-mrcjkb/rustaceanvim": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1766276825, "lastModified": 1768768642,
"narHash": "sha256-dcXnh5SYPh1VRctTuCnuVPKFQuAI4XEvQasolCOv+Xw=", "narHash": "sha256-tIIPP6RVzJTwEI2V5E7MZRM69cUV4xlNvwnF9PD71l4=",
"owner": "mrcjkb", "owner": "mrcjkb",
"repo": "rustaceanvim", "repo": "rustaceanvim",
"rev": "0fa0462a2d6c9629e0bd03d1902e6a1472ceac3e", "rev": "d09c0639e7f68615db6845570241947198234cd6",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -483,11 +531,11 @@
"nvim_plugin-neovim/nvim-lspconfig": { "nvim_plugin-neovim/nvim-lspconfig": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1766443238, "lastModified": 1769036040,
"narHash": "sha256-P95gPOwJ+rRofLb8iV5UOnh26to1I3sFrWGlGxHyz1M=", "narHash": "sha256-+KjXMTkVVVt3rpxQHRtrlT74DDsfRnPNUlqi/pvIMxg=",
"owner": "neovim", "owner": "neovim",
"repo": "nvim-lspconfig", "repo": "nvim-lspconfig",
"rev": "b34c08e0ea22bac67798f00238318fd16bd99b7c", "rev": "419b082102fa813739588dd82e19a8b6b2442855",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -496,22 +544,6 @@
"type": "github" "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": { "nvim_plugin-nvim-lua/plenary.nvim": {
"flake": false, "flake": false,
"locked": { "locked": {
@ -595,11 +627,11 @@
"nvim_plugin-nvim-telescope/telescope.nvim": { "nvim_plugin-nvim-telescope/telescope.nvim": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1766268405, "lastModified": 1768858021,
"narHash": "sha256-O1rUiVKpDSvKMkZMFaEd8/ACcSgO/lfa1+Hc8uHbFOI=", "narHash": "sha256-u1IyXfbGG2WF08V2mkGfjinBD2glU6aik7GjTFxyAn0=",
"owner": "nvim-telescope", "owner": "nvim-telescope",
"repo": "telescope.nvim", "repo": "telescope.nvim",
"rev": "e709d31454ee6e6157f0537f861f797bd44c0bad", "rev": "0d8b6eaa0b5ae6bb3d9785f7a3ba4a4c6c1b1af2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -611,11 +643,11 @@
"nvim_plugin-nvim-tree/nvim-tree.lua": { "nvim_plugin-nvim-tree/nvim-tree.lua": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1766192360, "lastModified": 1769045035,
"narHash": "sha256-Br+r9f/2o0AkewnGm7kFNfl3uYm1Akkklof0Sm5AL2M=", "narHash": "sha256-bRgYf9A2FZmlRFP7ixkfZqtOF+rQ+ju0vQ52qfmvY0A=",
"owner": "nvim-tree", "owner": "nvim-tree",
"repo": "nvim-tree.lua", "repo": "nvim-tree.lua",
"rev": "b8b44b6a2494d086a9177251a119f9daec6cace8", "rev": "869fc957edd43962c4cc7d70f0dca087056534c8",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -627,11 +659,11 @@
"nvim_plugin-nvim-tree/nvim-web-devicons": { "nvim_plugin-nvim-tree/nvim-web-devicons": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1766287594, "lastModified": 1768089403,
"narHash": "sha256-ZdFRd0//C0Lle4cYIoAHBdz/yvQqmeylLNwvSifaWm4=", "narHash": "sha256-x1ujwUXnRolP9SRUD7/Pb4/AZu+3YpC6CfGuq3Bn6Ew=",
"owner": "nvim-tree", "owner": "nvim-tree",
"repo": "nvim-web-devicons", "repo": "nvim-web-devicons",
"rev": "6788013bb9cb784e606ada44206b0e755e4323d7", "rev": "803353450c374192393f5387b6a0176d0972b848",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -755,11 +787,11 @@
"nvim_plugin-stevearc/conform.nvim": { "nvim_plugin-stevearc/conform.nvim": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1766346125, "lastModified": 1768760646,
"narHash": "sha256-Pp4bGTlZEqxHoHqVCEekDdg2jvNayxAuBReK4HJ6yGg=", "narHash": "sha256-M2mGNF8iARiQ6MzIFSSE/2BRDSj1+XEP/C44dwg8MQ8=",
"owner": "stevearc", "owner": "stevearc",
"repo": "conform.nvim", "repo": "conform.nvim",
"rev": "5420c4b5ea0aeb99c09cfbd4fd0b70d257b44f25", "rev": "c2526f1cde528a66e086ab1668e996d162c75f4f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -800,22 +832,6 @@
"type": "github" "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": { "nvim_plugin-uga-rosa/ccc.nvim": {
"flake": false, "flake": false,
"locked": { "locked": {
@ -835,11 +851,11 @@
"nvim_plugin-windwp/nvim-ts-autotag": { "nvim_plugin-windwp/nvim-ts-autotag": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1757545454, "lastModified": 1768909712,
"narHash": "sha256-nT2W5gKFEfzP7MztLjm7yqwam3ADk0svcMdLg2nmI/4=", "narHash": "sha256-XajbH3R1ONStQyYK6xQBE1cfGk3Y6tP/Mh9Ch90aKCk=",
"owner": "windwp", "owner": "windwp",
"repo": "nvim-ts-autotag", "repo": "nvim-ts-autotag",
"rev": "c4ca798ab95b316a768d51eaaaee48f64a4a46bc", "rev": "db15f2e0df2f5db916e511e3fffb682ef2f6354f",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -848,43 +864,10 @@
"type": "github" "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": { "root": {
"inputs": { "inputs": {
"nixpkgs": "nixpkgs", "nixpkgs": "nixpkgs",
"nvim_plugin-Almo7aya/openingh.nvim": "nvim_plugin-Almo7aya/openingh.nvim", "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-JoosepAlviste/nvim-ts-context-commentstring": "nvim_plugin-JoosepAlviste/nvim-ts-context-commentstring",
"nvim_plugin-L3MON4D3/LuaSnip": "nvim_plugin-L3MON4D3/LuaSnip", "nvim_plugin-L3MON4D3/LuaSnip": "nvim_plugin-L3MON4D3/LuaSnip",
"nvim_plugin-MeanderingProgrammer/render-markdown.nvim": "nvim_plugin-MeanderingProgrammer/render-markdown.nvim", "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-catppuccin/nvim": "nvim_plugin-catppuccin/nvim",
"nvim_plugin-chrisgrieser/nvim-early-retirement": "nvim_plugin-chrisgrieser/nvim-early-retirement", "nvim_plugin-chrisgrieser/nvim-early-retirement": "nvim_plugin-chrisgrieser/nvim-early-retirement",
"nvim_plugin-declancm/cinnamon.nvim": "nvim_plugin-declancm/cinnamon.nvim", "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/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-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-buffer": "nvim_plugin-hrsh7th/cmp-buffer",
"nvim_plugin-hrsh7th/cmp-nvim-lsp": "nvim_plugin-hrsh7th/cmp-nvim-lsp", "nvim_plugin-hrsh7th/cmp-nvim-lsp": "nvim_plugin-hrsh7th/cmp-nvim-lsp",
"nvim_plugin-hrsh7th/cmp-path": "nvim_plugin-hrsh7th/cmp-path", "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-mfussenegger/nvim-lint": "nvim_plugin-mfussenegger/nvim-lint",
"nvim_plugin-mrcjkb/rustaceanvim": "nvim_plugin-mrcjkb/rustaceanvim", "nvim_plugin-mrcjkb/rustaceanvim": "nvim_plugin-mrcjkb/rustaceanvim",
"nvim_plugin-neovim/nvim-lspconfig": "nvim_plugin-neovim/nvim-lspconfig", "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-lua/plenary.nvim": "nvim_plugin-nvim-lua/plenary.nvim",
"nvim_plugin-nvim-lualine/lualine.nvim": "nvim_plugin-nvim-lualine/lualine.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", "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/conform.nvim": "nvim_plugin-stevearc/conform.nvim",
"nvim_plugin-stevearc/dressing.nvim": "nvim_plugin-stevearc/dressing.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-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-uga-rosa/ccc.nvim": "nvim_plugin-uga-rosa/ccc.nvim",
"nvim_plugin-windwp/nvim-ts-autotag": "nvim_plugin-windwp/nvim-ts-autotag", "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" "rust-overlay": "rust-overlay"
} }
}, },
@ -947,11 +930,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1766457837, "lastModified": 1769091129,
"narHash": "sha256-aeBbkQ0HPFNOIsUeEsXmZHXbYq4bG8ipT9JRlCcKHgU=", "narHash": "sha256-Jj/vIHjiu4OdDIrDXZ3xOPCJrMZZKzhE2UIVXV/NYzY=",
"owner": "oxalica", "owner": "oxalica",
"repo": "rust-overlay", "repo": "rust-overlay",
"rev": "2c7510a559416d07242621d036847152d970612b", "rev": "131e22d6a6d54ab72aeef6a5a661ab7005b4c596",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -56,8 +56,6 @@
"nvim_plugin-JoosepAlviste/nvim-ts-context-commentstring".url = "nvim_plugin-JoosepAlviste/nvim-ts-context-commentstring".url =
"github:JoosepAlviste/nvim-ts-context-commentstring"; "github:JoosepAlviste/nvim-ts-context-commentstring";
"nvim_plugin-JoosepAlviste/nvim-ts-context-commentstring".flake = false; "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".url = "github:windwp/nvim-ts-autotag";
"nvim_plugin-windwp/nvim-ts-autotag".flake = false; "nvim_plugin-windwp/nvim-ts-autotag".flake = false;
"nvim_plugin-uga-rosa/ccc.nvim".url = "github:uga-rosa/ccc.nvim"; "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-MeanderingProgrammer/render-markdown.nvim".flake = false;
"nvim_plugin-Almo7aya/openingh.nvim".url = "github:Almo7aya/openingh.nvim"; "nvim_plugin-Almo7aya/openingh.nvim".url = "github:Almo7aya/openingh.nvim";
"nvim_plugin-Almo7aya/openingh.nvim".flake = false; "nvim_plugin-Almo7aya/openingh.nvim".flake = false;
"nvim_plugin-tpope/vim-surround".url = "github:tpope/vim-surround"; # mini.nvim replaces vim-surround, Comment.nvim
"nvim_plugin-tpope/vim-surround".flake = false; "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".url = "github:johmsalas/text-case.nvim";
"nvim_plugin-johmsalas/text-case.nvim".flake = false; "nvim_plugin-johmsalas/text-case.nvim".flake = false;
"nvim_plugin-mbbill/undotree".url = "github:mbbill/undotree"; "nvim_plugin-mbbill/undotree".url = "github:mbbill/undotree";
@ -96,10 +95,9 @@
"nvim_plugin-neovim/nvim-lspconfig".flake = false; "nvim_plugin-neovim/nvim-lspconfig".flake = false;
"nvim_plugin-b0o/schemastore.nvim".url = "github:b0o/schemastore.nvim"; "nvim_plugin-b0o/schemastore.nvim".url = "github:b0o/schemastore.nvim";
"nvim_plugin-b0o/schemastore.nvim".flake = false; "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".url = "github:hrsh7th/nvim-cmp";
"nvim_plugin-hrsh7th/nvim-cmp".flake = false; "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".url = "github:saadparwaiz1/cmp_luasnip";
"nvim_plugin-saadparwaiz1/cmp_luasnip".flake = false; "nvim_plugin-saadparwaiz1/cmp_luasnip".flake = false;
"nvim_plugin-hrsh7th/cmp-nvim-lsp".url = "github:hrsh7th/cmp-nvim-lsp"; "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-path".flake = false;
"nvim_plugin-hrsh7th/cmp-buffer".url = "github:hrsh7th/cmp-buffer"; "nvim_plugin-hrsh7th/cmp-buffer".url = "github:hrsh7th/cmp-buffer";
"nvim_plugin-hrsh7th/cmp-buffer".flake = false; "nvim_plugin-hrsh7th/cmp-buffer".flake = false;
"nvim_plugin-zbirenbaum/copilot-cmp".url = "github:zbirenbaum/copilot-cmp"; "nvim_plugin-L3MON4D3/LuaSnip".url = "github:L3MON4D3/LuaSnip";
"nvim_plugin-zbirenbaum/copilot-cmp".flake = false; "nvim_plugin-L3MON4D3/LuaSnip".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-stevearc/dressing.nvim".url = "github:stevearc/dressing.nvim"; "nvim_plugin-stevearc/dressing.nvim".url = "github:stevearc/dressing.nvim";
"nvim_plugin-stevearc/dressing.nvim".flake = false; "nvim_plugin-stevearc/dressing.nvim".flake = false;
"nvim_plugin-folke/neodev.nvim".url = "github:folke/neodev.nvim"; # lazydev.nvim replaces neodev.nvim (which is archived)
"nvim_plugin-folke/neodev.nvim".flake = false; "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".url = "github:mrcjkb/rustaceanvim";
"nvim_plugin-mrcjkb/rustaceanvim".flake = false; "nvim_plugin-mrcjkb/rustaceanvim".flake = false;
"nvim_plugin-Saecki/crates.nvim".url = "github:Saecki/crates.nvim"; "nvim_plugin-Saecki/crates.nvim".url = "github:Saecki/crates.nvim";
@ -196,6 +200,7 @@
glow glow
curl curl
sshfs sshfs
direnv # Auto-load project devShell environments
# nix lang stuff # nix lang stuff
nixfmt-rfc-style nixfmt-rfc-style

View file

@ -49,9 +49,9 @@ local function getSpec()
local p = ensure_table(plugin) local p = ensure_table(plugin)
if U.isArray(p) and #p > 1 then if U.isArray(p) and #p > 1 then
local plugins = {} local plugins = {}
table.foreachi(p, function(i, inner) for _, inner in ipairs(p) do
table.insert(plugins, convertPluginToNixStore(inner)) table.insert(plugins, convertPluginToNixStore(inner))
end) end
return plugins return plugins
end end
if p.enabled == false then if p.enabled == false then
@ -77,13 +77,15 @@ local function getSpec()
local plugins = {} local plugins = {}
local plugins_path = debug.getinfo(2, "S").source:sub(2):match("(.*/)") .. "lua/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 for _, file in ipairs(vim.fn.readdir(plugins_path)) do
if file:match("%.lua$") then
local plugin = string.sub(file, 0, -5) local plugin = string.sub(file, 0, -5)
local converted = convertPluginToNixStore(require("plugins." .. plugin)) local converted = convertPluginToNixStore(require("plugins." .. plugin))
if converted ~= nil then if converted ~= nil then
table.insert(plugins, converted) table.insert(plugins, converted)
end end
end end
end
return plugins return plugins
else else
return { { import = "plugins" } } return { { import = "plugins" } }

View file

@ -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
["<C-u>"] = cmp.mapping.scroll_docs(-4),
["<C-d>"] = cmp.mapping.scroll_docs(4),
["<C-e>"] = cmp.mapping.abort(),
["<esc>"] = 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),
-- ["<esc>"] = cmp.mapping.abort(),
-- Select the [n]ext item
["<C-j>"] = 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
["<C-k>"] = 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" }),
["<C-y>"] = cmp.mapping.confirm({ select = true }),
["<C-c>"] = 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,
}

View file

@ -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 = {
{
"<leader>/",
"<Plug>(comment_toggle_linewise_visual)",
'<ESC><CMD>lua require("Comment.api").locked("toggle.linewise")(vim.fn.visualmode())<CR>',
mode = { "x" },
desc = "Toggle comments on selection",
},
{
"<leader>/",
"V<Plug>(comment_toggle_linewise_visual)",
'<ESC><CMD>lua require("Comment.api").locked("toggle.linewise")(vim.fn.visualmode())<CR>',
mode = { "n" },
desc = "Toggle comments on line",
},
},
}

View file

@ -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({
["<C-j>"] = cmp.mapping.select_next_item(),
["<C-k>"] = cmp.mapping.select_prev_item(),
["<C-y>"] = cmp.mapping.confirm({ select = true }),
["<C-c>"] = cmp.mapping.complete(),
["<C-u>"] = cmp.mapping.scroll_docs(-4),
["<C-d>"] = cmp.mapping.scroll_docs(4),
["<C-e>"] = cmp.mapping.abort(),
["<Esc>"] = 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",
},
},
}

View file

@ -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 = {
{ "<leader>xx", "<cmd>Trouble diagnostics toggle<cr>", desc = "Diagnostics (Trouble)" },
{ "<leader>xX", "<cmd>Trouble diagnostics toggle filter.buf=0<cr>", desc = "Buffer Diagnostics (Trouble)" },
{ "<leader>xs", "<cmd>Trouble symbols toggle focus=false<cr>", desc = "Symbols (Trouble)" },
{ "<leader>xq", "<cmd>Trouble qflist toggle<cr>", desc = "Quickfix (Trouble)" },
{ "<leader>xl", "<cmd>Trouble loclist toggle<cr>", desc = "Location List (Trouble)" },
},
}

7
lua/plugins/direnv.lua Normal file
View file

@ -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,
}

12
lua/plugins/lazydev.lua Normal file
View file

@ -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" } },
},
},
}

View file

@ -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 <leader>,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 = {
{
"<leader>,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)",
},
},
}

View file

@ -11,12 +11,12 @@ vim.g.rustaceanvim = {
return { return {
-- LSP helper plugins for various languages -- 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... -- { 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", -- "mrcjkb/rustaceanvim",
-- -- uses ftplugins to enable itself lazily already -- -- uses ftplugins to enable itself lazily already
-- lazy = false, -- lazy = false,
-- }, -- }
-- TODO add some hotkeys for opening the popup menus on crates -- TODO add some hotkeys for opening the popup menus on crates
{ "Saecki/crates.nvim", event = "BufRead Cargo.toml", tag = "stable", opts = {}, main = "crates" }, { "Saecki/crates.nvim", event = "BufRead Cargo.toml", tag = "stable", opts = {}, main = "crates" },
{ {
@ -31,7 +31,6 @@ return {
"neovim/nvim-lspconfig", "neovim/nvim-lspconfig",
event = "BufEnter", event = "BufEnter",
dependencies = { dependencies = {
{ "hrsh7th/nvim-cmp" },
{ "b0o/schemastore.nvim" }, { "b0o/schemastore.nvim" },
-- Automatically install LSPs and related tools to stdpath for Neovim -- Automatically install LSPs and related tools to stdpath for Neovim
{ "williamboman/mason.nvim", enabled = not NIX, config = true }, -- NOTE: Must be loaded before dependants { "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() 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) U.safeRequire("cmp_nvim_lsp", function(c)
capabilities = vim.tbl_deep_extend("force", capabilities, c.default_capabilities()) capabilities = vim.tbl_deep_extend("force", capabilities, c.default_capabilities())
end) end)
@ -96,15 +96,7 @@ return {
completion = { completion = {
callSnippet = "Replace", callSnippet = "Replace",
}, },
workspace = { -- lazydev.nvim handles workspace library configuration
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 = { diagnostics = {
globals = { globals = {
"vim", "vim",
@ -115,7 +107,7 @@ return {
"hs", "hs",
}, },
}, },
}, telemetry = { enable = false },
}, },
}, },
}, },
@ -214,6 +206,52 @@ return {
pcall(vim.keymap.del, m.mode, m.lhs) pcall(vim.keymap.del, m.mode, m.lhs)
end 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 if NIX then
local lsp_servers = vim.tbl_keys(servers or {}) local lsp_servers = vim.tbl_keys(servers or {})
for _, server_name in ipairs(lsp_servers) do for _, server_name in ipairs(lsp_servers) do

63
lua/plugins/mini.lua Normal file
View file

@ -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 <leader>/ for comment toggle (matches old Comment.nvim binding)
vim.keymap.set("n", "<leader>/", function()
return require("mini.comment").operator() .. "_"
end, { expr = true, desc = "Toggle comment on line" })
vim.keymap.set("x", "<leader>/", 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
},
},
},
}

View file

@ -1,4 +0,0 @@
return {
"tpope/vim-surround",
event = "VeryLazy",
}

View file

@ -1,6 +1,8 @@
return { return {
"nvim-treesitter/nvim-treesitter", "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() init = function()
U.cmd_executable("tree-sitter", { U.cmd_executable("tree-sitter", {
[false] = function() [false] = function()
@ -8,48 +10,70 @@ return {
end, end,
}) })
end, end,
event = "BufRead", config = function()
cmd = { -- New nvim-treesitter API (post-rewrite)
"TSBufDisable", -- Setup is optional and only needed for non-default install directory
"TSBufEnable", local ts = require("nvim-treesitter")
"TSBufToggle",
"TSDisable", -- In nix mode, parsers are provided by the nix store, no installation needed
"TSEnable",
"TSToggle",
"TSInstall",
"TSInstallInfo",
"TSInstallSync",
"TSModuleInfo",
"TSUninstall",
"TSUpdate",
"TSUpdateSync",
},
opts = function()
local nonNixOpts = {}
if not NIX then if not NIX then
nonNixOpts = { -- Install common parsers (async)
ensure_installed = "all", ts.install({
auto_install = true, "bash",
} "c",
"css",
"dockerfile",
"go",
"html",
"javascript",
"json",
"lua",
"markdown",
"markdown_inline",
"nix",
"python",
"rust",
"svelte",
"toml",
"tsx",
"typescript",
"vim",
"vimdoc",
"yaml",
})
end end
return U.assign({
highlight = { -- Enable treesitter highlighting for all filetypes
enable = true, vim.api.nvim_create_autocmd("FileType", {
use_languagetree = true, group = vim.api.nvim_create_augroup("myconfig-treesitter-highlight", { clear = true }),
disable = function(lang, bufnr) callback = function(args)
if lang == "sql" then local bufnr = args.buf
return true local ft = args.match
-- Skip large files
if vim.api.nvim_buf_line_count(bufnr) > 4000 then
return
end end
return vim.api.nvim_buf_line_count(bufnr) > 4000
-- Skip sql (often has issues)
if ft == "sql" then
return
end
-- Enable treesitter highlighting
pcall(vim.treesitter.start, bufnr)
end, end,
additional_vim_regex_highlighting = false, })
},
incremental_selection = { enable = true }, -- Enable treesitter-based folding
indent = { enable = true }, vim.api.nvim_create_autocmd("FileType", {
autotag = { enable = true }, group = vim.api.nvim_create_augroup("myconfig-treesitter-fold", { clear = true }),
}, nonNixOpts) 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,
config = function(_, opts) })
require("nvim-treesitter.configs").setup(opts)
end, end,
} }

View file

@ -22,6 +22,7 @@ return {
{ "<leader>l", group = "LSP" }, { "<leader>l", group = "LSP" },
{ "<leader>lf", group = "LSP Find" }, { "<leader>lf", group = "LSP Find" },
{ "<leader>t", group = "Tabs" }, { "<leader>t", group = "Tabs" },
{ "<leader>x", group = "Trouble/Diagnostics" },
}, },
}, },
}, },

View file

@ -4,8 +4,8 @@ local function script_path()
end end
-- Extract the directory name from the script path -- Extract the directory name from the script path
local directory_name = script_path():match(".*/(.*)/") local directory_name = script_path():match(".*/(.*)/")
for _, file in ipairs(vim.fn.readdir(script_path(), [[v:val =~ '\.lua$']])) do for _, file in ipairs(vim.fn.readdir(script_path())) do
if file ~= "init.lua" then if file ~= "init.lua" and file:match("%.lua$") then
local neighbor = string.sub(file, 0, -5) local neighbor = string.sub(file, 0, -5)
require(directory_name .. "." .. neighbor) require(directory_name .. "." .. neighbor)
end end

535
todo.md Normal file
View file

@ -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: `<C-j>`/`<C-k>` select, `<C-y>` accept, `<C-u>`/`<C-d>` 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 `<leader>,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 `<leader>x`:
- `<leader>xx` - Toggle diagnostics
- `<leader>xX` - Buffer diagnostics only
- `<leader>xs` - Document symbols sidebar
- `<leader>xq` - Quickfix list
### 6.2 Update which-key
- [ ] Add `x` group: "Trouble/Diagnostics"
### 6.3 Optional: Telescope integration
- [ ] Add `<C-t>` 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: `<leader>/` 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:
- <C-j> = select_next
- <C-k> = select_prev
- <C-y> = accept
- <C-u> = scroll_documentation_up
- <C-d> = 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 <leader>,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:
- <leader>xx = Trouble diagnostics toggle
- <leader>xX = Trouble diagnostics toggle filter.buf=0
- <leader>xs = Trouble symbols toggle focus=false
- <leader>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 <leader>/ 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: { "<leader>x", group = "Trouble/Diagnostics" }
- Add group for llm toggle if not exists: under <leader>, 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 <leader>,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