mirror of
https://github.com/boxpositron/absolute-vim.git
synced 2026-10-24 05:23:19 +00:00
b4bb915a3f
Three-phase, single-branch plan derived from the modernization spec. Each phase is one commit with restart-and-validate gates. Phase 1 fixes critical bugs and removes abandoned plugins; phase 2 swaps notify/dressing for snacks UI; phase 3 swaps nvim-cmp for blink.cmp and telescope for snacks.picker.
1292 lines
36 KiB
Markdown
1292 lines
36 KiB
Markdown
# Neovim Modernization Implementation Plan
|
||
|
||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||
|
||
**Goal:** Modernize a Neovim 0.12 config by fixing four silent breakages, removing abandoned plugins, and swapping nvim-cmp + telescope + nvim-notify + dressing for blink.cmp + snacks.nvim.
|
||
|
||
**Architecture:** Three sequential phases on a single branch. Each phase ends in one commit. Tasks within a phase stage changes only — they do *not* commit individually. Restart Neovim and run the validation checklist at the end of each phase before moving on.
|
||
|
||
**Tech Stack:** Neovim 0.12, Lua, lazy.nvim, blink.cmp v1.x, snacks.nvim, gitsigns.nvim.
|
||
|
||
**Spec:** `docs/superpowers/specs/2026-05-02-nvim-modernization-design.md`.
|
||
|
||
**Working directory for all commands:** `/Users/davidibia/dotfiles/.config/nvim`.
|
||
|
||
---
|
||
|
||
## File map
|
||
|
||
### Phase 1 — Triage and deletions
|
||
|
||
**Modify:**
|
||
- `lua/absolute/remap.lua` — drop dead `<leader>j`/`<leader>k` lnext/lprev binding; rebind to `[l`/`]l`
|
||
- `lua/absolute/after/lsp-config.lua` — replace `vim.fn.sign_define` block with `vim.diagnostic.config`
|
||
- `lua/absolute/lazy.lua` — fix `require("../current-theme")` → `require("current-theme")`
|
||
- `lua/absolute/after/gitsigns.lua` — enable current-line blame
|
||
|
||
**Create:**
|
||
- `lua/absolute/plugins/snacks.lua` — top-level snacks.nvim spec (foundation only)
|
||
|
||
**Delete:**
|
||
- `lua/absolute/after/nvim-tree.lua` (orphan)
|
||
- `lua/absolute/plugins/nvim-treesitter-playground.lua`
|
||
- `lua/absolute/plugins/vim-maximizer.lua`
|
||
- `lua/absolute/plugins/poet-v.lua`
|
||
- `lua/absolute/after/poet-v.lua`
|
||
- `lua/absolute/plugins/render-markdown.lua`
|
||
- `lua/absolute/plugins/git-blame.lua`
|
||
- `lua/absolute/plugins/codecompanion.lua`
|
||
- `lua/absolute/after/codecompanion.lua`
|
||
- `lua/absolute/plugins/copilot.lua`
|
||
- `lua/absolute/plugins/gen.lua`
|
||
- `lua/absolute/after/gen.lua`
|
||
- `lua/absolute/plugins/llm.lua`
|
||
- `lua/absolute/after/llm.lua`
|
||
- `lua/absolute/plugins/opencode.lua`
|
||
- `lua/absolute/after/opencode.lua`
|
||
|
||
### Phase 2 — UI swap
|
||
|
||
**Modify:**
|
||
- `lua/absolute/plugins/snacks.lua` — enable `input` and `notifier` modules
|
||
|
||
**Delete:**
|
||
- `lua/absolute/plugins/notify.lua`
|
||
- `lua/absolute/after/notify.lua`
|
||
- `lua/absolute/plugins/dressing.lua`
|
||
|
||
### Phase 3 — Engine swaps
|
||
|
||
**Modify:**
|
||
- `lua/absolute/plugins/snacks.lua` — enable `picker` module
|
||
- `lua/absolute/after/lsp-config.lua` — swap capabilities provider; swap LSP picker keymaps
|
||
- `lua/absolute/remap.lua` — swap `<leader>?` keymap
|
||
- `lua/absolute/core/colorscheme.lua` — swap `<leader>cs`, drop `<leader>th`
|
||
- `lua/absolute/after/todo-comments.lua` — swap `<leader>pt` from `:TodoTelescope` to `Snacks.picker.todo_comments`
|
||
|
||
**Create:**
|
||
- `lua/absolute/plugins/blink-cmp.lua`
|
||
- `lua/absolute/after/blink-cmp.lua`
|
||
- `lua/absolute/after/snacks.lua` (replaces `after/telescope.lua`)
|
||
|
||
**Delete:**
|
||
- `lua/absolute/plugins/nvim-cmp.lua`
|
||
- `lua/absolute/after/nvim-cmp.lua`
|
||
- `lua/absolute/plugins/telescope.lua`
|
||
- `lua/absolute/after/telescope.lua`
|
||
- `lua/absolute/utils/telescope_image_preview.lua`
|
||
|
||
---
|
||
|
||
## Phase 1 — Triage and deletions
|
||
|
||
### Task 1.1: Fix keymap collision (C1)
|
||
|
||
**Files:**
|
||
- Modify: `lua/absolute/remap.lua`
|
||
|
||
- [ ] **Step 1: Open the file and confirm current state**
|
||
|
||
Run: `grep -n "leader>k\|leader>j\|lnext\|lprev" lua/absolute/remap.lua`
|
||
|
||
Expected output includes lines 70 (`<leader>k` lnext), 73 (`<leader>j` lprev), 120 (`<leader>k` resize), 124 (`<leader>j` resize).
|
||
|
||
- [ ] **Step 2: Replace the dead lnext/lprev lines with idiomatic location-list bracket pair**
|
||
|
||
Edit `lua/absolute/remap.lua`. Replace lines 69–73:
|
||
|
||
```lua
|
||
opts.desc = "Jump to next location and center screen"
|
||
vim.keymap.set("n", "<leader>k", "<cmd>lnext<CR>zz", opts)
|
||
|
||
opts.desc = "Jump to previous location and center screen"
|
||
vim.keymap.set("n", "<leader>j", "<cmd>lprev<CR>zz", opts)
|
||
```
|
||
|
||
with:
|
||
|
||
```lua
|
||
opts.desc = "Next location-list entry"
|
||
vim.keymap.set("n", "]l", "<cmd>lnext<CR>zz", opts)
|
||
|
||
opts.desc = "Previous location-list entry"
|
||
vim.keymap.set("n", "[l", "<cmd>lprev<CR>zz", opts)
|
||
```
|
||
|
||
- [ ] **Step 3: Verify the file parses**
|
||
|
||
Run: `nvim --headless -u NONE -c "luafile lua/absolute/remap.lua" -c "qa" 2>&1 | head -5`
|
||
|
||
Expected: no output (file loads clean) or only a "did not load mapleader" type warning. Any `E5113`/`E:` line is a failure — re-edit.
|
||
|
||
---
|
||
|
||
### Task 1.2: Migrate diagnostic-signs API (C2)
|
||
|
||
**Files:**
|
||
- Modify: `lua/absolute/after/lsp-config.lua:73-83`
|
||
|
||
- [ ] **Step 1: Open the file and confirm current sign_define block**
|
||
|
||
Run: `sed -n '72,84p' lua/absolute/after/lsp-config.lua`
|
||
|
||
Expected: lines 73–83 contain the `signs` table and the `for type, icon in pairs(signs)` loop calling `vim.fn.sign_define`.
|
||
|
||
- [ ] **Step 2: Replace the block**
|
||
|
||
In `lua/absolute/after/lsp-config.lua`, replace lines 73–83:
|
||
|
||
```lua
|
||
-- Change the Diagnostic symbols in the sign column (gutter)
|
||
local signs = {
|
||
Error = " ",
|
||
Warn = " ",
|
||
Hint = " ",
|
||
Info = " ",
|
||
}
|
||
|
||
for type, icon in pairs(signs) do
|
||
local hl = "DiagnosticSign" .. type
|
||
vim.fn.sign_define(hl, { text = icon, texthl = hl, numhl = "" })
|
||
end
|
||
```
|
||
|
||
with:
|
||
|
||
```lua
|
||
-- Configure diagnostic signs (Neovim 0.10+ API; required in 0.12)
|
||
vim.diagnostic.config({
|
||
signs = {
|
||
text = {
|
||
[vim.diagnostic.severity.ERROR] = " ",
|
||
[vim.diagnostic.severity.WARN] = " ",
|
||
[vim.diagnostic.severity.HINT] = " ",
|
||
[vim.diagnostic.severity.INFO] = " ",
|
||
},
|
||
},
|
||
})
|
||
```
|
||
|
||
- [ ] **Step 3: Verify file parses**
|
||
|
||
Run: `nvim --headless -u NONE -c "luafile lua/absolute/after/lsp-config.lua" -c "qa" 2>&1 | head -5`
|
||
|
||
Note: This will fail because the file requires `conform` and `cmp_nvim_lsp`, which aren't on `runtimepath` under `-u NONE`. That's expected. What you're checking for is *parse* errors (`E5113: Lua: ... unexpected symbol near ...`). If you see only `module not found` errors, the file parses.
|
||
|
||
---
|
||
|
||
### Task 1.3: Delete orphan after-file (C3)
|
||
|
||
**Files:**
|
||
- Delete: `lua/absolute/after/nvim-tree.lua`
|
||
|
||
- [ ] **Step 1: Confirm there is no plugin spec**
|
||
|
||
Run: `ls lua/absolute/plugins/ | grep -i nvim-tree`
|
||
|
||
Expected: empty output (no nvim-tree plugin spec exists).
|
||
|
||
- [ ] **Step 2: Confirm nothing else `require`s the orphan**
|
||
|
||
Run: `grep -rn "absolute.after.nvim-tree\|after.nvim-tree" lua/ init.lua 2>/dev/null`
|
||
|
||
Expected: empty output.
|
||
|
||
- [ ] **Step 3: Delete the file**
|
||
|
||
Run: `rm lua/absolute/after/nvim-tree.lua`
|
||
|
||
- [ ] **Step 4: Verify deletion**
|
||
|
||
Run: `ls lua/absolute/after/nvim-tree.lua 2>&1`
|
||
|
||
Expected: `ls: ...: No such file or directory`.
|
||
|
||
---
|
||
|
||
### Task 1.4: Fix require path in lazy.lua (C4)
|
||
|
||
**Files:**
|
||
- Modify: `lua/absolute/lazy.lua:36`
|
||
|
||
- [ ] **Step 1: Confirm current state**
|
||
|
||
Run: `sed -n '36p' lua/absolute/lazy.lua`
|
||
|
||
Expected: `require("../current-theme");`
|
||
|
||
- [ ] **Step 2: Edit the line**
|
||
|
||
In `lua/absolute/lazy.lua`, replace line 36:
|
||
|
||
```lua
|
||
require("../current-theme");
|
||
```
|
||
|
||
with:
|
||
|
||
```lua
|
||
require("current-theme")
|
||
```
|
||
|
||
(Drops the bogus `../` prefix and the unnecessary semicolon.)
|
||
|
||
- [ ] **Step 3: Verify file parses**
|
||
|
||
Run: `nvim --headless -u NONE -c "luafile lua/absolute/lazy.lua" -c "qa" 2>&1 | head -5`
|
||
|
||
Expected: parse-clean (module-not-found errors are fine; syntax errors are not).
|
||
|
||
---
|
||
|
||
### Task 1.5: Add foundation snacks.nvim spec
|
||
|
||
**Files:**
|
||
- Create: `lua/absolute/plugins/snacks.lua`
|
||
|
||
- [ ] **Step 1: Create the file**
|
||
|
||
Create `lua/absolute/plugins/snacks.lua`:
|
||
|
||
```lua
|
||
return {
|
||
"folke/snacks.nvim",
|
||
priority = 1000,
|
||
lazy = false,
|
||
---@type snacks.Config
|
||
opts = {
|
||
bigfile = { enabled = true },
|
||
quickfile = { enabled = true },
|
||
-- input, notifier added in Phase 2
|
||
-- picker added in Phase 3
|
||
},
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: Verify file parses**
|
||
|
||
Run: `nvim --headless -u NONE -c "luafile lua/absolute/plugins/snacks.lua" -c "qa" 2>&1 | head -5`
|
||
|
||
Expected: parse-clean.
|
||
|
||
---
|
||
|
||
### Task 1.6: Enable gitsigns current-line blame
|
||
|
||
**Files:**
|
||
- Modify: `lua/absolute/after/gitsigns.lua`
|
||
|
||
- [ ] **Step 1: Confirm current contents**
|
||
|
||
Run: `cat lua/absolute/after/gitsigns.lua`
|
||
|
||
Expected:
|
||
|
||
```lua
|
||
local gitsigns = require("gitsigns")
|
||
|
||
gitsigns.setup()
|
||
```
|
||
|
||
- [ ] **Step 2: Replace the file contents**
|
||
|
||
Replace the entire contents of `lua/absolute/after/gitsigns.lua` with:
|
||
|
||
```lua
|
||
local gitsigns = require("gitsigns")
|
||
|
||
gitsigns.setup({
|
||
current_line_blame = true,
|
||
current_line_blame_opts = {
|
||
virt_text_pos = "eol",
|
||
delay = 500,
|
||
ignore_whitespace = false,
|
||
},
|
||
})
|
||
```
|
||
|
||
- [ ] **Step 3: Verify file parses**
|
||
|
||
Run: `nvim --headless -u NONE -c "luafile lua/absolute/after/gitsigns.lua" -c "qa" 2>&1 | head -5`
|
||
|
||
Expected: parse-clean (a "module gitsigns not found" error is fine).
|
||
|
||
---
|
||
|
||
### Task 1.7: Delete abandoned plugin specs
|
||
|
||
**Files:**
|
||
- Delete: `lua/absolute/plugins/nvim-treesitter-playground.lua`
|
||
- Delete: `lua/absolute/plugins/vim-maximizer.lua`
|
||
- Delete: `lua/absolute/plugins/poet-v.lua`
|
||
- Delete: `lua/absolute/after/poet-v.lua`
|
||
- Delete: `lua/absolute/plugins/render-markdown.lua`
|
||
- Delete: `lua/absolute/plugins/git-blame.lua`
|
||
|
||
- [ ] **Step 1: Verify no references in remaining code**
|
||
|
||
Run:
|
||
```bash
|
||
grep -rn "playground\|vim-maximizer\|poet-v\|render-markdown\|git-blame\|gitblame" lua/ init.lua 2>/dev/null | grep -v "lua/absolute/plugins/nvim-treesitter-playground.lua\|lua/absolute/plugins/vim-maximizer.lua\|lua/absolute/plugins/poet-v.lua\|lua/absolute/after/poet-v.lua\|lua/absolute/plugins/render-markdown.lua\|lua/absolute/plugins/git-blame.lua"
|
||
```
|
||
|
||
Expected output may include:
|
||
- `lua/absolute/plugins/codecompanion.lua` mentioning `render-markdown` in its `ft = { "markdown", "codecompanion" }` (the `render-markdown.lua` spec) — that's fine, codecompanion is being deleted in Task 1.8.
|
||
- Comments mentioning old gitsigns/git-blame — fine.
|
||
|
||
If anything else lights up (e.g. an active `require("git-blame")`), **stop and address it** before deleting.
|
||
|
||
- [ ] **Step 2: Delete the six files**
|
||
|
||
Run:
|
||
```bash
|
||
rm lua/absolute/plugins/nvim-treesitter-playground.lua \
|
||
lua/absolute/plugins/vim-maximizer.lua \
|
||
lua/absolute/plugins/poet-v.lua \
|
||
lua/absolute/after/poet-v.lua \
|
||
lua/absolute/plugins/render-markdown.lua \
|
||
lua/absolute/plugins/git-blame.lua
|
||
```
|
||
|
||
- [ ] **Step 3: Verify all six are gone**
|
||
|
||
Run:
|
||
```bash
|
||
ls lua/absolute/plugins/nvim-treesitter-playground.lua \
|
||
lua/absolute/plugins/vim-maximizer.lua \
|
||
lua/absolute/plugins/poet-v.lua \
|
||
lua/absolute/after/poet-v.lua \
|
||
lua/absolute/plugins/render-markdown.lua \
|
||
lua/absolute/plugins/git-blame.lua 2>&1
|
||
```
|
||
|
||
Expected: each line reports `No such file or directory`.
|
||
|
||
---
|
||
|
||
### Task 1.8: Delete AI plugin specs
|
||
|
||
**Files:**
|
||
- Delete: `lua/absolute/plugins/codecompanion.lua`
|
||
- Delete: `lua/absolute/after/codecompanion.lua`
|
||
- Delete: `lua/absolute/plugins/copilot.lua`
|
||
- Delete: `lua/absolute/plugins/gen.lua`
|
||
- Delete: `lua/absolute/after/gen.lua`
|
||
- Delete: `lua/absolute/plugins/llm.lua`
|
||
- Delete: `lua/absolute/after/llm.lua`
|
||
- Delete: `lua/absolute/plugins/opencode.lua`
|
||
- Delete: `lua/absolute/after/opencode.lua`
|
||
|
||
- [ ] **Step 1: Verify no references elsewhere**
|
||
|
||
Run:
|
||
```bash
|
||
grep -rn "codecompanion\|copilot\|gen.nvim\|huggingface/llm\|opencode" lua/ init.lua 2>/dev/null \
|
||
| grep -v "lua/absolute/plugins/codecompanion.lua\|lua/absolute/after/codecompanion.lua\|lua/absolute/plugins/copilot.lua\|lua/absolute/plugins/gen.lua\|lua/absolute/after/gen.lua\|lua/absolute/plugins/llm.lua\|lua/absolute/after/llm.lua\|lua/absolute/plugins/opencode.lua\|lua/absolute/after/opencode.lua"
|
||
```
|
||
|
||
Expected: empty output (or only comments).
|
||
|
||
If you see live references in the toggleterm config (`_OLLAMA_TOGGLE` is fine — that's an Ollama terminal, not gen.nvim), in markview, or anywhere else, **stop and remove those references first.**
|
||
|
||
- [ ] **Step 2: Delete the nine files**
|
||
|
||
Run:
|
||
```bash
|
||
rm lua/absolute/plugins/codecompanion.lua \
|
||
lua/absolute/after/codecompanion.lua \
|
||
lua/absolute/plugins/copilot.lua \
|
||
lua/absolute/plugins/gen.lua \
|
||
lua/absolute/after/gen.lua \
|
||
lua/absolute/plugins/llm.lua \
|
||
lua/absolute/after/llm.lua \
|
||
lua/absolute/plugins/opencode.lua \
|
||
lua/absolute/after/opencode.lua
|
||
```
|
||
|
||
- [ ] **Step 3: Verify deletion**
|
||
|
||
Run:
|
||
```bash
|
||
ls lua/absolute/plugins/codecompanion.lua lua/absolute/after/codecompanion.lua \
|
||
lua/absolute/plugins/copilot.lua \
|
||
lua/absolute/plugins/gen.lua lua/absolute/after/gen.lua \
|
||
lua/absolute/plugins/llm.lua lua/absolute/after/llm.lua \
|
||
lua/absolute/plugins/opencode.lua lua/absolute/after/opencode.lua 2>&1
|
||
```
|
||
|
||
Expected: every line reports `No such file or directory`.
|
||
|
||
---
|
||
|
||
### Task 1.9: Validate and commit Phase 1
|
||
|
||
- [ ] **Step 1: Show pending changes**
|
||
|
||
Run: `git status`
|
||
|
||
Expected: modifications to `remap.lua`, `after/lsp-config.lua`, `lazy.lua`, `after/gitsigns.lua`, plus the previously-modified `core/colorscheme.lua`, `core/init.lua`, `lazy-lock.json`, `plugins/codecompanion.lua` (now deleted), `plugins/copilot.lua` (now deleted), `plugins/venv-selector.lua`, `lua/current-theme.lua`. New files: `plugins/snacks.lua`, `core/theme-registry.lua`, `plugins/flash.lua`. Many `D` (deleted) entries.
|
||
|
||
- [ ] **Step 2: Run Neovim once to bootstrap snacks and clean orphans**
|
||
|
||
Run: `nvim --headless "+Lazy! sync" "+Lazy! clean" "+qa" 2>&1 | tail -20`
|
||
|
||
Expected: lazy installs `snacks.nvim`, removes `playground`, `vim-maximizer`, `poet-v`, `git-blame.nvim`, `render-markdown.nvim`, `codecompanion.nvim`, `copilot.vim`, `gen.nvim`, `llm.nvim`, `opencode.nvim`. No errors.
|
||
|
||
- [ ] **Step 3: Open Neovim interactively and run validation checklist**
|
||
|
||
Run: `nvim`
|
||
|
||
In Neovim:
|
||
1. `:messages` — should be empty of `E:` lines.
|
||
2. `:Lazy` — should show `snacks.nvim` installed; should NOT list `nvim-notify`-replacement plugins yet (those come in Phase 2).
|
||
3. `:checkhealth lspconfig` — diagnostic signs section should not warn about `sign_define`.
|
||
4. Open a Lua file with a syntax error (e.g. `:e /tmp/bad.lua`, type `local x =`); confirm error gutter sign renders.
|
||
5. `:Inspect`, `:InspectTree`, `:EditQuery` — all three open without errors (proves treesitter playground replacement).
|
||
6. Open a git-tracked file, position cursor on a line with prior commit history; after ~500 ms confirm virtual blame text appears at end of line.
|
||
7. Press `<leader>k` and `<leader>j` in normal mode — current window should resize vertically (no `E:` errors).
|
||
8. Press `]l` and `[l` — should move through the location list (or report "location list empty"; either is fine).
|
||
9. `:q`
|
||
|
||
If anything fails, roll back individually-suspect files with `git checkout -- <file>` and address before continuing.
|
||
|
||
- [ ] **Step 4: Stage and commit Phase 1**
|
||
|
||
Run:
|
||
```bash
|
||
git add lua/absolute/remap.lua \
|
||
lua/absolute/after/lsp-config.lua \
|
||
lua/absolute/lazy.lua \
|
||
lua/absolute/after/gitsigns.lua \
|
||
lua/absolute/plugins/snacks.lua \
|
||
lua/absolute/core/theme-registry.lua \
|
||
lua/absolute/plugins/flash.lua \
|
||
lua/absolute/core/colorscheme.lua \
|
||
lua/absolute/core/init.lua \
|
||
lua/absolute/plugins/venv-selector.lua \
|
||
lua/current-theme.lua \
|
||
lazy-lock.json
|
||
git add -u # picks up the deletions
|
||
```
|
||
|
||
- [ ] **Step 5: Verify the staged set**
|
||
|
||
Run: `git status`
|
||
|
||
Expected: green entries match the file map for Phase 1; nothing in red.
|
||
|
||
- [ ] **Step 6: Commit**
|
||
|
||
Run:
|
||
```bash
|
||
git commit -m "$(cat <<'EOF'
|
||
feat(nvim): phase 1 — triage and abandoned-plugin cleanup
|
||
|
||
Fix keymap collision on <leader>j/<leader>k (now resize-only;
|
||
location-list moved to ]l/[l). Migrate diagnostic signs from
|
||
deprecated vim.fn.sign_define to vim.diagnostic.config. Drop
|
||
orphan after/nvim-tree.lua and the bogus require("../current-theme").
|
||
Add foundation snacks.nvim spec. Remove playground, vim-maximizer,
|
||
poet-v, git-blame, render-markdown, and all five AI plugin specs.
|
||
Enable gitsigns current_line_blame.
|
||
|
||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
EOF
|
||
)"
|
||
```
|
||
|
||
- [ ] **Step 7: Verify commit**
|
||
|
||
Run: `git log -1 --stat`
|
||
|
||
Expected: shows the Phase 1 commit with file list matching the file map above.
|
||
|
||
---
|
||
|
||
## Phase 2 — UI swap
|
||
|
||
### Task 2.1: Enable snacks input and notifier
|
||
|
||
**Files:**
|
||
- Modify: `lua/absolute/plugins/snacks.lua`
|
||
|
||
- [ ] **Step 1: Replace the file contents**
|
||
|
||
Replace the entire contents of `lua/absolute/plugins/snacks.lua` with:
|
||
|
||
```lua
|
||
return {
|
||
"folke/snacks.nvim",
|
||
priority = 1000,
|
||
lazy = false,
|
||
---@type snacks.Config
|
||
opts = {
|
||
bigfile = { enabled = true },
|
||
quickfile = { enabled = true },
|
||
input = { enabled = true },
|
||
notifier = {
|
||
enabled = true,
|
||
timeout = 3000,
|
||
style = "compact",
|
||
top_down = true,
|
||
icons = {
|
||
debug = "",
|
||
error = "",
|
||
info = "",
|
||
trace = "✎",
|
||
warn = "",
|
||
},
|
||
},
|
||
-- picker added in Phase 3
|
||
},
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: Verify file parses**
|
||
|
||
Run: `nvim --headless -u NONE -c "luafile lua/absolute/plugins/snacks.lua" -c "qa" 2>&1 | head -5`
|
||
|
||
Expected: parse-clean.
|
||
|
||
---
|
||
|
||
### Task 2.2: Delete nvim-notify and dressing
|
||
|
||
**Files:**
|
||
- Delete: `lua/absolute/plugins/notify.lua`
|
||
- Delete: `lua/absolute/after/notify.lua`
|
||
- Delete: `lua/absolute/plugins/dressing.lua`
|
||
|
||
- [ ] **Step 1: Verify no live references**
|
||
|
||
Run:
|
||
```bash
|
||
grep -rn "rcarriga/nvim-notify\|require(\"notify\")\|stevearc/dressing\|require(\"dressing\")" lua/ init.lua 2>/dev/null \
|
||
| grep -v "lua/absolute/plugins/notify.lua\|lua/absolute/after/notify.lua\|lua/absolute/plugins/dressing.lua"
|
||
```
|
||
|
||
Expected: empty.
|
||
|
||
- [ ] **Step 2: Delete the three files**
|
||
|
||
Run:
|
||
```bash
|
||
rm lua/absolute/plugins/notify.lua \
|
||
lua/absolute/after/notify.lua \
|
||
lua/absolute/plugins/dressing.lua
|
||
```
|
||
|
||
- [ ] **Step 3: Verify deletion**
|
||
|
||
Run:
|
||
```bash
|
||
ls lua/absolute/plugins/notify.lua \
|
||
lua/absolute/after/notify.lua \
|
||
lua/absolute/plugins/dressing.lua 2>&1
|
||
```
|
||
|
||
Expected: each line reports `No such file or directory`.
|
||
|
||
---
|
||
|
||
### Task 2.3: Validate and commit Phase 2
|
||
|
||
- [ ] **Step 1: Sync lazy and prune**
|
||
|
||
Run: `nvim --headless "+Lazy! sync" "+Lazy! clean" "+qa" 2>&1 | tail -20`
|
||
|
||
Expected: lazy removes `nvim-notify` and `dressing.nvim`. No errors.
|
||
|
||
- [ ] **Step 2: Validate interactively**
|
||
|
||
Run: `nvim`
|
||
|
||
In Neovim:
|
||
1. `:messages` — clean.
|
||
2. `:lua vim.notify("Phase 2 OK", vim.log.levels.INFO)` — compact toast appears top-right.
|
||
3. `:lua vim.notify("Test warn", vim.log.levels.WARN)` — warning-styled toast.
|
||
4. `<leader>rn` on a symbol in a code file — centered floating prompt appears (proves `vim.ui.input` override).
|
||
5. `<leader>ca` on a code-action target — selection menu uses snacks picker UI (proves `vim.ui.select` override; picker not yet enabled, so this routes through snacks.input).
|
||
6. `:q`
|
||
|
||
- [ ] **Step 3: Stage and commit Phase 2**
|
||
|
||
Run:
|
||
```bash
|
||
git add lua/absolute/plugins/snacks.lua lazy-lock.json
|
||
git add -u
|
||
git commit -m "$(cat <<'EOF'
|
||
feat(nvim): phase 2 — replace nvim-notify and dressing with snacks
|
||
|
||
Enable snacks.input and snacks.notifier modules; remove the
|
||
now-redundant nvim-notify and archived dressing.nvim specs.
|
||
Notifier preserves the prior icons and 3000 ms timeout.
|
||
|
||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
EOF
|
||
)"
|
||
```
|
||
|
||
- [ ] **Step 4: Verify commit**
|
||
|
||
Run: `git log -1 --stat`
|
||
|
||
Expected: shows the Phase 2 commit.
|
||
|
||
---
|
||
|
||
## Phase 3 — Engine swaps
|
||
|
||
### Task 3.1: Add blink.cmp plugin spec
|
||
|
||
**Files:**
|
||
- Create: `lua/absolute/plugins/blink-cmp.lua`
|
||
|
||
- [ ] **Step 1: Create the file**
|
||
|
||
Create `lua/absolute/plugins/blink-cmp.lua`:
|
||
|
||
```lua
|
||
return {
|
||
"saghen/blink.cmp",
|
||
version = "1.*",
|
||
event = "InsertEnter",
|
||
dependencies = { "rafamadriz/friendly-snippets" },
|
||
config = function()
|
||
require("absolute.after.blink-cmp")
|
||
end,
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: Verify file parses**
|
||
|
||
Run: `nvim --headless -u NONE -c "luafile lua/absolute/plugins/blink-cmp.lua" -c "qa" 2>&1 | head -5`
|
||
|
||
Expected: parse-clean.
|
||
|
||
---
|
||
|
||
### Task 3.2: Add blink.cmp configuration
|
||
|
||
**Files:**
|
||
- Create: `lua/absolute/after/blink-cmp.lua`
|
||
|
||
- [ ] **Step 1: Create the file**
|
||
|
||
Create `lua/absolute/after/blink-cmp.lua`:
|
||
|
||
```lua
|
||
require("blink.cmp").setup({
|
||
keymap = { preset = "default" },
|
||
appearance = {
|
||
nerd_font_variant = "mono",
|
||
},
|
||
sources = {
|
||
default = { "lsp", "path", "snippets", "buffer" },
|
||
},
|
||
cmdline = {
|
||
keymap = { preset = "cmdline" },
|
||
completion = { menu = { auto_show = true } },
|
||
},
|
||
signature = { enabled = true },
|
||
})
|
||
```
|
||
|
||
- [ ] **Step 2: Verify file parses**
|
||
|
||
Run: `nvim --headless -u NONE -c "luafile lua/absolute/after/blink-cmp.lua" -c "qa" 2>&1 | head -5`
|
||
|
||
Expected: parse-clean (`module blink.cmp not found` is fine; syntax errors are not).
|
||
|
||
---
|
||
|
||
### Task 3.3: Migrate LSP capabilities provider to blink
|
||
|
||
**Files:**
|
||
- Modify: `lua/absolute/after/lsp-config.lua:3,70`
|
||
|
||
- [ ] **Step 1: Confirm current state**
|
||
|
||
Run: `sed -n '1,5p;68,72p' lua/absolute/after/lsp-config.lua`
|
||
|
||
Expected: line 3 is `local cmp_nvim_lsp = require("cmp_nvim_lsp")`; line 70 is `local capabilities = cmp_nvim_lsp.default_capabilities()`.
|
||
|
||
- [ ] **Step 2: Edit line 3**
|
||
|
||
In `lua/absolute/after/lsp-config.lua`, replace line 3:
|
||
|
||
```lua
|
||
local cmp_nvim_lsp = require("cmp_nvim_lsp")
|
||
```
|
||
|
||
with: *(delete the line entirely)*. Make sure no blank line is left between `local conform = require("conform")` and the next non-blank line.
|
||
|
||
- [ ] **Step 3: Edit the capabilities line**
|
||
|
||
In the same file, replace the line:
|
||
|
||
```lua
|
||
local capabilities = cmp_nvim_lsp.default_capabilities()
|
||
```
|
||
|
||
with:
|
||
|
||
```lua
|
||
local capabilities = require("blink.cmp").get_lsp_capabilities()
|
||
```
|
||
|
||
- [ ] **Step 4: Verify the edit**
|
||
|
||
Run: `grep -n "capabilities\|cmp_nvim_lsp\|blink" lua/absolute/after/lsp-config.lua | head -10`
|
||
|
||
Expected: no `cmp_nvim_lsp` references; one `blink.cmp` reference; many `capabilities = capabilities` reuses.
|
||
|
||
---
|
||
|
||
### Task 3.4: Delete nvim-cmp specs
|
||
|
||
**Files:**
|
||
- Delete: `lua/absolute/plugins/nvim-cmp.lua`
|
||
- Delete: `lua/absolute/after/nvim-cmp.lua`
|
||
|
||
- [ ] **Step 1: Verify no live references outside the doomed files**
|
||
|
||
Run:
|
||
```bash
|
||
grep -rn "hrsh7th/nvim-cmp\|require(\"cmp\")\|require(\"cmp_nvim_lsp\")\|require(\"luasnip\")\|require(\"lspkind\")" lua/ init.lua 2>/dev/null \
|
||
| grep -v "lua/absolute/plugins/nvim-cmp.lua\|lua/absolute/after/nvim-cmp.lua"
|
||
```
|
||
|
||
Expected: empty (the LSP capabilities reference was removed in Task 3.3).
|
||
|
||
If anything else lights up — e.g. another plugin that called `cmp.register_source` — pause and migrate that reference before continuing.
|
||
|
||
- [ ] **Step 2: Delete the two files**
|
||
|
||
Run:
|
||
```bash
|
||
rm lua/absolute/plugins/nvim-cmp.lua \
|
||
lua/absolute/after/nvim-cmp.lua
|
||
```
|
||
|
||
- [ ] **Step 3: Verify deletion**
|
||
|
||
Run: `ls lua/absolute/plugins/nvim-cmp.lua lua/absolute/after/nvim-cmp.lua 2>&1`
|
||
|
||
Expected: each line reports `No such file or directory`.
|
||
|
||
---
|
||
|
||
### Task 3.5: Enable snacks picker module
|
||
|
||
**Files:**
|
||
- Modify: `lua/absolute/plugins/snacks.lua`
|
||
|
||
- [ ] **Step 1: Replace the file contents**
|
||
|
||
Replace the entire contents of `lua/absolute/plugins/snacks.lua` with:
|
||
|
||
```lua
|
||
return {
|
||
"folke/snacks.nvim",
|
||
priority = 1000,
|
||
lazy = false,
|
||
---@type snacks.Config
|
||
opts = {
|
||
bigfile = { enabled = true },
|
||
quickfile = { enabled = true },
|
||
input = { enabled = true },
|
||
notifier = {
|
||
enabled = true,
|
||
timeout = 3000,
|
||
style = "compact",
|
||
top_down = true,
|
||
icons = {
|
||
debug = "",
|
||
error = "",
|
||
info = "",
|
||
trace = "✎",
|
||
warn = "",
|
||
},
|
||
},
|
||
picker = {
|
||
enabled = true,
|
||
ui_select = true,
|
||
},
|
||
},
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 2: Verify file parses**
|
||
|
||
Run: `nvim --headless -u NONE -c "luafile lua/absolute/plugins/snacks.lua" -c "qa" 2>&1 | head -5`
|
||
|
||
Expected: parse-clean.
|
||
|
||
---
|
||
|
||
### Task 3.6: Add new after/snacks.lua with picker keymaps
|
||
|
||
**Files:**
|
||
- Create: `lua/absolute/after/snacks.lua`
|
||
|
||
- [ ] **Step 1: Create the file**
|
||
|
||
Create `lua/absolute/after/snacks.lua`:
|
||
|
||
```lua
|
||
local map = vim.keymap.set
|
||
|
||
local function with_desc(desc)
|
||
return { noremap = true, silent = true, desc = desc }
|
||
end
|
||
|
||
map("n", "<C-p>", function()
|
||
Snacks.picker.files()
|
||
end, with_desc("Find files"))
|
||
|
||
map("n", "<leader>gf", function()
|
||
Snacks.picker.git_files()
|
||
end, with_desc("Find git files"))
|
||
|
||
map("n", "<leader>pr", function()
|
||
Snacks.picker.recent()
|
||
end, with_desc("Recent files"))
|
||
|
||
map("n", "<leader>ps", function()
|
||
Snacks.picker.grep()
|
||
end, with_desc("Live grep"))
|
||
|
||
map("n", "<leader>sb", function()
|
||
Snacks.picker.grep_word()
|
||
end, with_desc("Grep word under cursor"))
|
||
|
||
map("n", "<leader>pf", function()
|
||
Snacks.picker.explorer()
|
||
end, with_desc("File explorer (cwd)"))
|
||
|
||
map("n", "<leader>cf", function()
|
||
Snacks.picker.explorer({ cwd = vim.fn.expand("%:p:h") })
|
||
end, with_desc("File explorer (current file dir)"))
|
||
```
|
||
|
||
Note: snacks auto-loads its `after/plugin/snacks.vim` shim that creates the `Snacks` global, so the `function()` wrappers (rather than direct references) are required to defer global lookup until the keymap fires.
|
||
|
||
- [ ] **Step 2: Verify file parses**
|
||
|
||
Run: `nvim --headless -u NONE -c "luafile lua/absolute/after/snacks.lua" -c "qa" 2>&1 | head -5`
|
||
|
||
Expected: parse-clean. (The `Snacks` global won't exist under `-u NONE`, but that's a runtime concern, not a parse error.)
|
||
|
||
- [ ] **Step 3: Wire the after-file into the plugin spec**
|
||
|
||
Edit `lua/absolute/plugins/snacks.lua` to call the new after-file. Replace the entire contents with:
|
||
|
||
```lua
|
||
return {
|
||
"folke/snacks.nvim",
|
||
priority = 1000,
|
||
lazy = false,
|
||
---@type snacks.Config
|
||
opts = {
|
||
bigfile = { enabled = true },
|
||
quickfile = { enabled = true },
|
||
input = { enabled = true },
|
||
notifier = {
|
||
enabled = true,
|
||
timeout = 3000,
|
||
style = "compact",
|
||
top_down = true,
|
||
icons = {
|
||
debug = "",
|
||
error = "",
|
||
info = "",
|
||
trace = "✎",
|
||
warn = "",
|
||
},
|
||
},
|
||
picker = {
|
||
enabled = true,
|
||
ui_select = true,
|
||
},
|
||
},
|
||
config = function(_, opts)
|
||
require("snacks").setup(opts)
|
||
require("absolute.after.snacks")
|
||
end,
|
||
}
|
||
```
|
||
|
||
- [ ] **Step 4: Verify the spec parses**
|
||
|
||
Run: `nvim --headless -u NONE -c "luafile lua/absolute/plugins/snacks.lua" -c "qa" 2>&1 | head -5`
|
||
|
||
Expected: parse-clean.
|
||
|
||
---
|
||
|
||
### Task 3.7: Migrate `<leader>?` keymap in remap.lua
|
||
|
||
**Files:**
|
||
- Modify: `lua/absolute/remap.lua:7`
|
||
|
||
- [ ] **Step 1: Confirm current state**
|
||
|
||
Run: `sed -n '6,8p' lua/absolute/remap.lua`
|
||
|
||
Expected:
|
||
```lua
|
||
opts.desc = "Show Keymap"
|
||
vim.keymap.set("n", "<leader>?", "<cmd>Telescope keymaps<CR>", opts) -- toggle file explorer
|
||
```
|
||
|
||
- [ ] **Step 2: Edit the binding**
|
||
|
||
Replace those two lines in `lua/absolute/remap.lua`:
|
||
|
||
```lua
|
||
opts.desc = "Show Keymap"
|
||
vim.keymap.set("n", "<leader>?", "<cmd>Telescope keymaps<CR>", opts) -- toggle file explorer
|
||
```
|
||
|
||
with:
|
||
|
||
```lua
|
||
opts.desc = "Show keymaps"
|
||
vim.keymap.set("n", "<leader>?", function()
|
||
Snacks.picker.keymaps()
|
||
end, opts)
|
||
```
|
||
|
||
- [ ] **Step 3: Verify file parses**
|
||
|
||
Run: `nvim --headless -u NONE -c "luafile lua/absolute/remap.lua" -c "qa" 2>&1 | head -5`
|
||
|
||
Expected: parse-clean.
|
||
|
||
---
|
||
|
||
### Task 3.8: Migrate keymaps in colorscheme.lua
|
||
|
||
**Files:**
|
||
- Modify: `lua/absolute/core/colorscheme.lua:147-153`
|
||
|
||
- [ ] **Step 1: Confirm current state**
|
||
|
||
Run: `sed -n '147,154p' lua/absolute/core/colorscheme.lua`
|
||
|
||
Expected:
|
||
```lua
|
||
local opts = { noremap = true, silent = true }
|
||
|
||
opts.desc = "Fuzzy find colorschemes"
|
||
vim.api.nvim_set_keymap("n", "<leader>cs", "<cmd>Telescope colorscheme<CR>", opts)
|
||
|
||
opts.desc = "Fuzzy find themes"
|
||
vim.api.nvim_set_keymap("n", "<leader>th", "<cmd>Telescope themes<CR>", opts)
|
||
```
|
||
|
||
- [ ] **Step 2: Replace the block**
|
||
|
||
Replace those eight lines (inclusive of the trailing blank if present) with:
|
||
|
||
```lua
|
||
local opts = { noremap = true, silent = true }
|
||
|
||
opts.desc = "Fuzzy find colorschemes"
|
||
vim.keymap.set("n", "<leader>cs", function()
|
||
Snacks.picker.colorschemes()
|
||
end, opts)
|
||
```
|
||
|
||
(Drops `<leader>th` per the spec — the registry-aware behavior fires on `ColorScheme` autocmds regardless of how the colorscheme is selected.)
|
||
|
||
- [ ] **Step 3: Verify file parses**
|
||
|
||
Run: `nvim --headless -u NONE -c "luafile lua/absolute/core/colorscheme.lua" -c "qa" 2>&1 | head -5`
|
||
|
||
Expected: parse-clean (a "module absolute.core.theme-registry not found" error is fine).
|
||
|
||
---
|
||
|
||
### Task 3.9: Migrate `<leader>pt` in todo-comments.lua
|
||
|
||
**Files:**
|
||
- Modify: `lua/absolute/after/todo-comments.lua:17-20`
|
||
|
||
- [ ] **Step 1: Confirm current state**
|
||
|
||
Run: `sed -n '17,21p' lua/absolute/after/todo-comments.lua`
|
||
|
||
Expected:
|
||
```lua
|
||
opts.desc = "Open Comments in Telescope"
|
||
vim.keymap.set("n", "<leader>pt", function()
|
||
vim.cmd([[TodoTelescope]])
|
||
end, opts)
|
||
```
|
||
|
||
- [ ] **Step 2: Replace the block**
|
||
|
||
Replace those four lines in `lua/absolute/after/todo-comments.lua`:
|
||
|
||
```lua
|
||
opts.desc = "Open Comments in Telescope"
|
||
vim.keymap.set("n", "<leader>pt", function()
|
||
vim.cmd([[TodoTelescope]])
|
||
end, opts)
|
||
```
|
||
|
||
with:
|
||
|
||
```lua
|
||
opts.desc = "Open todo comments in picker"
|
||
vim.keymap.set("n", "<leader>pt", function()
|
||
Snacks.picker.todo_comments()
|
||
end, opts)
|
||
```
|
||
|
||
- [ ] **Step 3: Verify file parses**
|
||
|
||
Run: `nvim --headless -u NONE -c "luafile lua/absolute/after/todo-comments.lua" -c "qa" 2>&1 | head -5`
|
||
|
||
Expected: parse-clean.
|
||
|
||
---
|
||
|
||
### Task 3.10: Migrate LSP picker keymaps in lsp-config.lua
|
||
|
||
**Files:**
|
||
- Modify: `lua/absolute/after/lsp-config.lua:20,26,38,47`
|
||
|
||
- [ ] **Step 1: Confirm current state**
|
||
|
||
Run: `grep -n "Telescope" lua/absolute/after/lsp-config.lua`
|
||
|
||
Expected:
|
||
```
|
||
20: vim.keymap.set("n", "gd", "<cmd>Telescope lsp_definitions<CR>", opts)
|
||
26: vim.keymap.set("n", "gi", "<cmd>Telescope lsp_implementations<CR>", opts)
|
||
38: vim.keymap.set("n", "gt", "<cmd>Telescope lsp_type_definitions<CR>", opts)
|
||
47: vim.keymap.set("n", "<leader>cr", "<cmd>Telescope lsp_references<CR>", opts)
|
||
```
|
||
|
||
- [ ] **Step 2: Replace each binding**
|
||
|
||
Make four individual edits in `lua/absolute/after/lsp-config.lua`:
|
||
|
||
Replace line 20:
|
||
|
||
```lua
|
||
vim.keymap.set("n", "gd", "<cmd>Telescope lsp_definitions<CR>", opts)
|
||
```
|
||
|
||
with:
|
||
|
||
```lua
|
||
vim.keymap.set("n", "gd", function() Snacks.picker.lsp_definitions() end, opts)
|
||
```
|
||
|
||
Replace line 26:
|
||
|
||
```lua
|
||
vim.keymap.set("n", "gi", "<cmd>Telescope lsp_implementations<CR>", opts)
|
||
```
|
||
|
||
with:
|
||
|
||
```lua
|
||
vim.keymap.set("n", "gi", function() Snacks.picker.lsp_implementations() end, opts)
|
||
```
|
||
|
||
Replace line 38:
|
||
|
||
```lua
|
||
vim.keymap.set("n", "gt", "<cmd>Telescope lsp_type_definitions<CR>", opts)
|
||
```
|
||
|
||
with:
|
||
|
||
```lua
|
||
vim.keymap.set("n", "gt", function() Snacks.picker.lsp_type_definitions() end, opts)
|
||
```
|
||
|
||
Replace line 47:
|
||
|
||
```lua
|
||
vim.keymap.set("n", "<leader>cr", "<cmd>Telescope lsp_references<CR>", opts)
|
||
```
|
||
|
||
with:
|
||
|
||
```lua
|
||
vim.keymap.set("n", "<leader>cr", function() Snacks.picker.lsp_references() end, opts)
|
||
```
|
||
|
||
- [ ] **Step 3: Verify**
|
||
|
||
Run: `grep -n "Telescope\|Snacks.picker" lua/absolute/after/lsp-config.lua`
|
||
|
||
Expected: zero `Telescope` matches; four `Snacks.picker.lsp_*` matches.
|
||
|
||
---
|
||
|
||
### Task 3.11: Delete telescope ecosystem
|
||
|
||
**Files:**
|
||
- Delete: `lua/absolute/plugins/telescope.lua`
|
||
- Delete: `lua/absolute/after/telescope.lua`
|
||
- Delete: `lua/absolute/utils/telescope_image_preview.lua`
|
||
|
||
- [ ] **Step 1: Verify no live references remain**
|
||
|
||
Run:
|
||
```bash
|
||
grep -rn "Telescope\|require(\"telescope\|telescope.builtin\|telescope_image_preview\|nvim-telescope" lua/ init.lua 2>/dev/null \
|
||
| grep -v "lua/absolute/plugins/telescope.lua\|lua/absolute/after/telescope.lua\|lua/absolute/utils/telescope_image_preview.lua"
|
||
```
|
||
|
||
Expected: empty.
|
||
|
||
If anything else lights up — e.g. a custom command, a comment that's actually executable — pause and migrate before deleting.
|
||
|
||
- [ ] **Step 2: Delete the three files**
|
||
|
||
Run:
|
||
```bash
|
||
rm lua/absolute/plugins/telescope.lua \
|
||
lua/absolute/after/telescope.lua \
|
||
lua/absolute/utils/telescope_image_preview.lua
|
||
```
|
||
|
||
- [ ] **Step 3: Verify deletion**
|
||
|
||
Run:
|
||
```bash
|
||
ls lua/absolute/plugins/telescope.lua \
|
||
lua/absolute/after/telescope.lua \
|
||
lua/absolute/utils/telescope_image_preview.lua 2>&1
|
||
```
|
||
|
||
Expected: each line reports `No such file or directory`.
|
||
|
||
---
|
||
|
||
### Task 3.12: Validate and commit Phase 3
|
||
|
||
- [ ] **Step 1: Sync lazy and prune**
|
||
|
||
Run: `nvim --headless "+Lazy! sync" "+Lazy! clean" "+qa" 2>&1 | tail -30`
|
||
|
||
Expected:
|
||
- lazy installs `blink.cmp` (and downloads its Rust matcher binary; first run takes longer).
|
||
- lazy removes `telescope.nvim`, `telescope-file-browser.nvim`, `telescope-live-grep-args.nvim`, `telescope-media-files.nvim`, `telescope-themes`, `telescope-dap.nvim`, `popup.nvim`, `nvim-cmp`, `cmp-nvim-lsp`, `cmp-buffer`, `cmp-path`, `cmp-cmdline`, `cmp_luasnip`, `LuaSnip`, `lspkind.nvim`.
|
||
- No errors.
|
||
|
||
- [ ] **Step 2: Run `:checkhealth blink.cmp`**
|
||
|
||
Run: `nvim --headless "+checkhealth blink.cmp" "+qa" 2>&1 | tail -40`
|
||
|
||
Expected: green checks for `vim.snippet`, fuzzy matcher binary, and at least one source.
|
||
|
||
- [ ] **Step 3: Validate interactively**
|
||
|
||
Run: `nvim`
|
||
|
||
In Neovim:
|
||
1. `:messages` — clean.
|
||
2. Open a Lua file. Type `vim.l` and confirm a blink completion menu appears with LSP entries.
|
||
3. With the menu open: `<C-n>`/`<C-p>` navigate; `<C-y>` accepts.
|
||
4. In Lua, type `for<Tab>` — confirm the `friendly-snippets` `for` snippet expands.
|
||
5. Type `:Lazy <Tab>` in cmdline — confirm cmdline completion shows.
|
||
6. Press `K` on a symbol — LSP hover floats appear.
|
||
7. Press `gd` on a symbol — `Snacks.picker.lsp_definitions` opens.
|
||
8. Press `gi` on a symbol — `Snacks.picker.lsp_implementations` opens.
|
||
9. Press `gt` on a symbol — `Snacks.picker.lsp_type_definitions` opens.
|
||
10. Press `<leader>cr` on a symbol — `Snacks.picker.lsp_references` opens.
|
||
11. Press `<C-p>` — file picker; preview pane works.
|
||
12. Press `<leader>gf` — git files; preview works.
|
||
13. Press `<leader>pr` — recent files.
|
||
14. Press `<leader>ps` — live grep; type `function`; results stream in.
|
||
15. Press `<leader>sb` on a word — grep word under cursor; results show.
|
||
16. Press `<leader>pf` — file explorer at cwd.
|
||
17. Press `<leader>cf` — file explorer at current file's directory.
|
||
18. Press `<leader>?` — keymaps picker.
|
||
19. Press `<leader>cs` — colorscheme picker; pick a theme; confirm wezterm/ghostty sync still fires.
|
||
20. Press `<leader>pt` — todo-comments picker.
|
||
21. `:q`
|
||
|
||
If any binding fails, run `:lua print(vim.inspect(vim.api.nvim_get_keymap("n")))` to inspect the actual binding state and re-edit the source file.
|
||
|
||
- [ ] **Step 4: Stage and commit Phase 3**
|
||
|
||
Run:
|
||
```bash
|
||
git add lua/absolute/plugins/blink-cmp.lua \
|
||
lua/absolute/after/blink-cmp.lua \
|
||
lua/absolute/after/snacks.lua \
|
||
lua/absolute/plugins/snacks.lua \
|
||
lua/absolute/after/lsp-config.lua \
|
||
lua/absolute/remap.lua \
|
||
lua/absolute/core/colorscheme.lua \
|
||
lua/absolute/after/todo-comments.lua \
|
||
lazy-lock.json
|
||
git add -u
|
||
git commit -m "$(cat <<'EOF'
|
||
feat(nvim): phase 3 — replace nvim-cmp with blink.cmp and telescope with snacks.picker
|
||
|
||
Swap the completion engine to blink.cmp v1.x, dropping nvim-cmp,
|
||
its eight cmp-* sources, lspkind, and LuaSnip. Swap the picker
|
||
to snacks.picker, removing telescope.nvim and six telescope
|
||
extensions. LSP capabilities now sourced from blink.cmp; LSP
|
||
navigation keymaps and the colorscheme/keymaps/todo pickers move
|
||
to Snacks.picker. friendly-snippets is preserved as blink's
|
||
snippet source.
|
||
|
||
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
||
EOF
|
||
)"
|
||
```
|
||
|
||
- [ ] **Step 5: Verify commit and overall branch state**
|
||
|
||
Run: `git log --oneline -4`
|
||
|
||
Expected (most recent first):
|
||
```
|
||
<sha> feat(nvim): phase 3 — replace nvim-cmp with blink.cmp and telescope with snacks.picker
|
||
<sha> feat(nvim): phase 2 — replace nvim-notify and dressing with snacks
|
||
<sha> feat(nvim): phase 1 — triage and abandoned-plugin cleanup
|
||
fd3878b docs(spec): add nvim modernization design
|
||
```
|
||
|
||
Run: `git diff --stat HEAD~3 HEAD | tail -3`
|
||
|
||
Expected: large net negative line count (~hundreds of lines deleted, fewer added).
|
||
|
||
---
|
||
|
||
## Done. Acceptance verification
|
||
|
||
- [ ] **Final acceptance check**
|
||
|
||
Run:
|
||
```bash
|
||
grep -E '"(nvim-cmp|cmp-buffer|cmp-cmdline|cmp-path|cmp_luasnip|cmp-nvim-lsp|lspkind\.nvim|LuaSnip|telescope\.nvim|telescope-file-browser\.nvim|telescope-live-grep-args\.nvim|telescope-media-files\.nvim|telescope-themes|telescope-dap\.nvim|popup\.nvim|nvim-notify|dressing\.nvim|playground|vim-maximizer|poet-v|git-blame\.nvim|render-markdown\.nvim|codecompanion\.nvim|copilot\.vim|gen\.nvim|llm\.nvim|opencode\.nvim)"' lazy-lock.json
|
||
```
|
||
|
||
Expected: empty output (every removed plugin is gone from the lockfile).
|
||
|
||
Run:
|
||
```bash
|
||
grep -E '"(blink\.cmp|snacks\.nvim)"' lazy-lock.json
|
||
```
|
||
|
||
Expected: both lines present.
|
||
|
||
Run: `grep -rn "vim.fn.sign_define\|require(\"cmp_nvim_lsp\")\|require(\"telescope\)" lua/ init.lua 2>/dev/null`
|
||
|
||
Expected: empty.
|
||
|
||
If all three checks pass, the implementation matches the spec.
|