fix(nvim): migrate config to Neovim 0.13 - #8
Conversation
Co-authored-by: Cursor <cursoragent@cursor.com>
nvim-treesitter main no longer ships textobjects.scm, which made mini.ai raise E5108 for Lua. Add nvim-treesitter-textobjects, prefer vim.uv, and harden treesitter FileType start while keeping AI/LSP support. Co-authored-by: Cursor <cursoragent@cursor.com>
WalkthroughThe PR targets Neovim 0.13 compatibility. It updates runtime APIs, Treesitter and editor integrations, language-server configuration, tool installation, plugin locks, and automated compatibility measurements. ChangesNeovim 0.13 compatibility
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Script as .auto/measure.sh
participant Neovim as Neovim 0.13
participant Config as tiny-nvim configuration
participant Treesitter as Treesitter and textobjects
participant LSP as Language servers
participant Metrics as Compatibility metrics
Script->>Neovim: Run bounded headless checks
Neovim->>Config: Load Lua configuration
Config->>Treesitter: Start parsers and query textobjects
Config->>LSP: Configure and attach language servers
Treesitter-->>Config: Return parser and query results
LSP-->>Config: Return initialized clients
Config-->>Neovim: Provide check results
Neovim-->>Script: Return failures and messages
Script->>Metrics: Aggregate failures and startup timings
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
lua/plugins/ui.lua (1)
371-382: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winExplicit args are safer and clearer for
vim.treesitter.start.Line 382 calls
pcall(vim.treesitter.start)with no arguments. This relies on the implicit current buffer and its filetype-derived language. Line 378 already computeslangfor the membership check at line 379, but line 382 does not reuse it. Passev.bufandlangexplicitly, matching the pattern that Neovim's own documentation and thenvim-treesitterREADME use inFileTypeautocmd examples.Separately,
opts(line 372) still containsensure_installed, a field the newnvim-treesittermain-branchsetup()no longer recognizes (installation moved to a separate.install()call, already used at line 374). Passing it intoTS.setup(opts)most likely has no effect, but it can mislead readers into thinkingsetup()still handles installation.♻️ Proposed fix for explicit `vim.treesitter.start` arguments
local lang = vim.treesitter.language.get_lang(ev.match) or ev.match if not vim.tbl_contains(opts.ensure_installed or {}, lang) then return end - pcall(vim.treesitter.start) + pcall(vim.treesitter.start, ev.buf, lang)Confirm whether
nvim-treesittermain branch'ssetup()tolerates or ignores unrecognized keys such asensure_installed, since the README states the setup schema is minimal.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lua/plugins/ui.lua` around lines 371 - 382, Update the FileType autocmd callback around vim.treesitter.start to call it through pcall with ev.buf and the already computed lang explicitly. Remove ensure_installed from the options passed to TS.setup, while retaining it for TS.install and the parser membership check; verify the current nvim-treesitter setup behavior for unrecognized keys and keep the setup options limited to supported fields.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.auto/measure.sh:
- Line 8: Replace the machine-specific NVIM defaults in .auto/measure.sh lines
8-8 and .auto/checks.sh lines 12-12 with a PATH-resolved nvim fallback while
preserving NVIM_BIN overrides.
- Around line 267-279: Update the sorted-array assignment in the warm startup
median logic to use mapfile with the sorted times output, replacing the unquoted
command substitution while preserving numeric ordering and the subsequent
startup_ms selection.
In @.auto/prompt.md:
- Line 23: Update the Neovim binary reference documented in .auto/prompt.md to
avoid the host-specific absolute path, and reference the existing NVIM variable,
PATH lookup, or mise-managed command consistently with .auto/measure.sh so the
instructions work on other hosts.
- Around line 38-40: Update .auto/measure.sh so fail_lsp distinguishes exact
missing-workspace-tooling signatures from genuine LSP compatibility failures:
define the permitted TS/Rust missing-tooling patterns explicitly and exempt only
those patterns when LSP_INIT is absent. Keep all other TS/Rust initialization
errors counted, and align the startup-message filtering with the same narrowly
defined signatures.
---
Nitpick comments:
In `@lua/plugins/ui.lua`:
- Around line 371-382: Update the FileType autocmd callback around
vim.treesitter.start to call it through pcall with ev.buf and the already
computed lang explicitly. Remove ensure_installed from the options passed to
TS.setup, while retaining it for TS.install and the parser membership check;
verify the current nvim-treesitter setup behavior for unrecognized keys and keep
the setup options limited to supported fields.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 9a431486-193c-46dd-86e8-b5151ca31026
📒 Files selected for processing (12)
.auto/checks.sh.auto/config.json.auto/fixtures/sample.lua.auto/fixtures/sample.md.auto/measure.sh.auto/prompt.mdinit.lualazy-lock.jsonlua/langs/markdown.lualua/plugins/coding.lualua/plugins/extra/codecompanion.lualua/plugins/ui.lua
|
c57b948 to
c16e33f
Compare
Result: {"status":"keep","metric":0,"compat_failures":0,"startup_ms":649,"fail_binary":0,"fail_startup":0,"fail_messages":0,"fail_deprecated":0,"fail_loadfile":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_vim_loop":0,"fail_treesitter":0,"fail_ai":0,"fail_lsp":0,"fail_miniai":0}
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":624}
Result: {"status":"keep","metric":0,"compat_failures":0,"startup_ms":629,"fail_binary":0,"fail_startup":0,"fail_messages":0,"fail_deprecated":0,"fail_loadfile":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_vim_loop":0,"fail_treesitter":0,"fail_ai":0,"fail_lsp":0,"fail_miniai":0}
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":655}
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":635}
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":637}
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":640}
vscode S: treesitter expand via flash nodes
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":625}
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":651}
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":639}
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":644}
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":653}
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":643}
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":638}
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":641}
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":623}
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":638}
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (2)
lua/utils/vscode_treesitter.lua (1)
129-129: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueOmit parentheses for single-string
requirecalls.
lua/utils/vscode_treesitter.lua#L129-L129: Changerequire("vscode")torequire "vscode".lua/utils/vscode_treesitter.lua#L152-L152: Changerequire("vscode")torequire "vscode".lua/plugins/flash.lua#L11-L13: Changerequire("utils.vscode_treesitter")torequire "utils.vscode_treesitter".lua/plugins/flash.lua#L35-L40: Change both single-stringrequire(...)calls to the no-parentheses form.lua/config/keymaps.lua#L40-L48: Change both single-stringrequire(...)calls to the no-parentheses form.lua/plugins/vscode.lua#L99-L113: Change both single-stringrequire(...)calls to the no-parentheses form.lua/plugins/oil.lua#L105-L111: Changerequire("oil")torequire "oil".As per coding guidelines, “Lua call parentheses: omit for single string argument.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lua/utils/vscode_treesitter.lua` at line 129, Apply the Lua single-string call style consistently: remove parentheses from each listed require call in lua/utils/vscode_treesitter.lua (129-129 and 152-152), lua/plugins/flash.lua (11-13 and 35-40), lua/config/keymaps.lua (40-48), lua/plugins/vscode.lua (99-113), and lua/plugins/oil.lua (105-111), preserving all required module names and surrounding calls.Source: Coding guidelines
.auto/ideas.md (1)
6-6: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick winAdd a first-directory startup check.
This note identifies a boundary that can break the first directory buffer. Add a harness case that starts Neovim with a directory path, passes the first
BufEnter, and verifies the expected Oil or VS Code parent-navigation owner. Include the check in the compatibility check set instead of relying only on aggregatecompat_failures.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In @.auto/ideas.md at line 6, Add a compatibility harness case for launching Neovim with a directory path, explicitly passing the first BufEnter event and asserting the expected Oil or VS Code parent-navigation owner. Register this case in the compatibility check set so its result is reported individually rather than only through aggregate compat_failures.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.auto/ideas.md:
- Around line 5-7: Resolve the conflicting incremental-selection notes in
.auto/ideas.md: either document the feature only for the correct supported
Neovim version with the tested an/in mappings, or remove the item if Neovim 0.13
does not ship those keymaps. Keep the g<Space> documentation note and oil
initialization item unchanged.
In @.auto/log.jsonl:
- Around line 1-3: Normalize the JSONL record format in the logging flow that
emits init, result, and run entries, using a shared schema version or
compatibility-metrics output format. Ensure future compat_failures records
explicitly identify the check set and do not imply that partial metrics
represent the full suite; preserve line 2 as valid JSON and do not address this
as a blank-line parsing issue.
In `@lua/utils/vscode_treesitter.lua`:
- Around line 141-149: Update the match-to-item conversion loop to translate the
Neovim byte offsets in match.pos[2] and match.end_pos[2] + 1 into UTF-16 columns
before assigning character and endCharacter. Use the existing line text/source
to perform the conversion and cap each converted column at the line’s UTF-16
length, preserving the current line and label mappings.
In `@scripts/install-tools.sh`:
- Line 41: Update the installer flow around the mise setup and the
command-availability selection so a failed `mise use -g tree-sitter@latest` does
not select mise as the provider. Fall through to the existing cargo and npm
installation paths when mise cannot install tree-sitter, while preserving the
current selection when mise succeeds.
---
Nitpick comments:
In @.auto/ideas.md:
- Line 6: Add a compatibility harness case for launching Neovim with a directory
path, explicitly passing the first BufEnter event and asserting the expected Oil
or VS Code parent-navigation owner. Register this case in the compatibility
check set so its result is reported individually rather than only through
aggregate compat_failures.
In `@lua/utils/vscode_treesitter.lua`:
- Line 129: Apply the Lua single-string call style consistently: remove
parentheses from each listed require call in lua/utils/vscode_treesitter.lua
(129-129 and 152-152), lua/plugins/flash.lua (11-13 and 35-40),
lua/config/keymaps.lua (40-48), lua/plugins/vscode.lua (99-113), and
lua/plugins/oil.lua (105-111), preserving all required module names and
surrounding calls.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: c6e8cb54-5e24-4106-a3b6-a1ff42b50013
📒 Files selected for processing (11)
.auto/ideas.md.auto/log.jsonllua/config/keymaps.lualua/config/options.lualua/plugins/flash.lualua/plugins/oil.lualua/plugins/ui.lualua/plugins/vscode.lualua/utils/flash_hacks.lualua/utils/vscode_treesitter.luascripts/install-tools.sh
🚧 Files skipped from review as they are similar to previous changes (1)
- lua/plugins/ui.lua
| {"event":"init","name":"Neovim 0.13 config migration","metric_name":"compat_failures","direction":"lower","unit":"count"} | ||
| {"event":"result","iteration":0,"description":"post-fix baseline after textobjects+vim.uv","decision":"keep","metrics":{"compat_failures":0,"startup_ms":677,"fail_miniai":0,"fail_treesitter":0,"fail_ai":0,"fail_lsp":0,"fail_vim_loop":0},"asi":{"root_cause":"nvim-treesitter main dropped textobjects.scm; mini.ai needs nvim-treesitter-textobjects","supports":["treesitter","ai","lsp","miniai"]}} | ||
| {"run":1,"commit":"16697fc","metric":0,"metrics":{"compat_failures":0,"startup_ms":649,"fail_binary":0,"fail_startup":0,"fail_messages":0,"fail_deprecated":0,"fail_loadfile":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_vim_loop":0,"fail_treesitter":0,"fail_ai":0,"fail_lsp":0,"fail_miniai":0},"status":"keep","description":"Disable nvim.dir; vscode - reveals explorer; oil owns -","timestamp":1785776603428,"segment":0,"confidence":null,"asi":{"hypothesis":"Disable nvim.dir (0.13) early; remap - to VS Code explorer under vscode-neovim; oil owns - in terminal","metric_note":"compat_failures already 0 (floor); keep UX/compat fix without regression","user_request":"fix - opening buffer tree in vscode-neovim","supports":["treesitter","ai","lsp","miniai"],"root_cause":"runtime/plugin/dir.lua maps - to nvim-dir-up"}} |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
rg -n --hidden --glob '!**/.git/**' \
'(\.auto/log\.jsonl|metric_name|compat_failures|fail_[A-Za-z0-9_]+|iteration|run|status)' .
python - <<'PY'
import json
from pathlib import Path
path = Path(".auto/log.jsonl")
shapes = {}
for line_number, raw in enumerate(path.read_text().splitlines(), 1):
if not raw.strip():
print(f"{line_number}: blank record")
continue
record = json.loads(raw)
shapes.setdefault(tuple(sorted(record)), []).append(line_number)
for shape, lines in shapes.items():
print(lines, shape)
PYRepository: jellydn/tiny-nvim
Length of output: 26308
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
cat -n .auto/log.jsonl
printf '\n--- .auto/measure.sh relevant sections ---\n'
cat -n .auto/measure.sh | sed -n '1,80p;240,300p'
printf '\n--- .auto/prompt.md -- compatibility check context ---\n'
cat -n .auto/prompt.md | sed -n '1,70p'
printf '\n--- .auto/checks.sh top ---\n'
cat -n .auto/checks.sh | sed -n '1,80p'Repository: jellydn/tiny-nvim
Length of output: 25351
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
import json
log = Path(".auto/log.jsonl")
lines = log.read_text().splitlines()
schema_versions = []
distinguisher_shapes = {}
blank_lines = []
for idx, line in enumerate(lines, 1):
stripped = line.strip()
if not stripped:
blank_lines.append(idx)
continue
obj = json.loads(stripped)
schema_versions.append(obj.get("schema_version"))
keys = tuple(sorted(obj))
distinguisher_shapes.setdefault(keys, []).append(idx)
print("blank_line_indices", blank_lines)
print("schema_version_values", schema_versions)
print("keys_per_record")
for keys, idxs in sorted(distinguisher_shapes.items()):
print("indices", idxs, "keys", keys)
record_events = [json.loads(line)["event"] if json.loads(line).get("event") is not None else "NO_EVENT" for line in lines if line.strip()]
record_runs = []
checks_present_by_record = {}
for idx, line in enumerate(lines, 1):
if not line.strip():
continue
obj = json.loads(line)
if "run" in obj:
record_runs.append(obj)
checks = sorted(k for k in (obj.get("metrics") or {}).key() if k.startswith("fail_"))
checks_present_by_record[idx] = checks
print("event_values", record_events)
print("run_ids", [r["run"] for r in record_runs])
print("checks_present_by_record", checks_present_by_record)
PYRepository: jellydn/tiny-nvim
Length of output: 787
Normalize .auto/log.jsonl record schemas before changing new entries.
The log has three distinct JSON record shapes: an init metadata record, a result iteration record with only some fail_* metrics, and run records with the full check set. Line 2 is valid JSONL, so this should not be fixed as a blank-line parser issue. Add a shared schema version or output format for compatibility metrics so future compat_failures: 0 records do not imply a changed or partial check set.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.auto/log.jsonl around lines 1 - 3, Normalize the JSONL record format in the
logging flow that emits init, result, and run entries, using a shared schema
version or compatibility-metrics output format. Ensure future compat_failures
records explicitly identify the check set and do not imply that partial metrics
represent the full suite; preserve line 2 as valid JSON and do not address this
as a blank-line parsing issue.
|
Addressed CodeRabbit review comments in the latest commit:
Skipped (not actionable for this repo):
|
Portable NVIM_BIN/PATH for harness, UTF-16 columns for vscode flash labels, tree-sitter install fallthrough, and clarify LSP noise / log schema docs. Co-authored-by: Cursor <cursoragent@cursor.com>
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":639}
Portable NVIM_BIN/PATH for harness, UTF-16 columns for vscode flash labels, tree-sitter install fallthrough, and clarify LSP noise / log schema docs. Co-authored-by: Cursor <cursoragent@cursor.com>
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":653}
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":631}
aa744b6 to
2e6da6a
Compare
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (2)
init.lua (1)
36-42: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winRename the LSP mapping table to PascalCase.
lsp_by_ftis a Lua table. Rename it toLspByFtand update its local references.As per coding guidelines, “Use
PascalCasefor Lua modules and tables.”🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@init.lua` around lines 36 - 42, Rename the local LSP mapping table from lsp_by_ft to LspByFt and update every reference to it within the surrounding configuration, preserving all existing mappings and behavior.Source: Coding guidelines
lua/config/autocmds.lua (1)
213-214: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winUse the required
requirecall style.Bind the module with
local lsp_utils = require "utils.lsp". Then calllsp_utils.on_attach(client, args.buf).As per coding guidelines, “Lua call parentheses: omit for single string argument.”
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@lua/config/autocmds.lua` around lines 213 - 214, Update the LspAttach handler around the require call to bind the module as local lsp_utils using the parentheses-free single-string require style, then invoke lsp_utils.on_attach(client, args.buf) instead of requiring the module inline.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In @.auto/log.jsonl:
- Around line 19-21: Update the run records emitted in the logging path to
include explicit schema_version metadata and a check-set marker, matching the
schema_version 1 contract documented in .auto/ideas.md. Apply the fields
consistently to every record type, including partial result records, and
preserve the existing run metrics and metadata.
In `@lua/utils/lsp.lua`:
- Around line 27-31: Update the buffer keymap setup around
_tiny_nvim_lsp_keymaps so it does not return solely because an earlier client
marked the buffer complete. Track installation per capability-dependent key, or
otherwise continue checking each client’s capabilities, ensuring later clients
can install maps such as gd when they provide definitionProvider.
- Around line 137-145: Update M.ruff_cmd() to return an explicit unavailable
result when no validated executable is found instead of falling back to {
"ruff", "server" }. In lsp/ruff.lua, check that result before starting the Ruff
LSP and skip setup when unavailable, preventing Neovim from retrying an
unsupported PATH executable.
---
Nitpick comments:
In `@init.lua`:
- Around line 36-42: Rename the local LSP mapping table from lsp_by_ft to
LspByFt and update every reference to it within the surrounding configuration,
preserving all existing mappings and behavior.
In `@lua/config/autocmds.lua`:
- Around line 213-214: Update the LspAttach handler around the require call to
bind the module as local lsp_utils using the parentheses-free single-string
require style, then invoke lsp_utils.on_attach(client, args.buf) instead of
requiring the module inline.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 071c3a48-6f83-4456-9c41-cf4db6659383
📒 Files selected for processing (20)
.auto/checks.sh.auto/ideas.md.auto/log.jsonl.auto/measure.sh.auto/prompt.mdREADME.mdinit.lualsp/basedpyright.lualsp/gopls.lualsp/lua_ls.lualsp/ruff.lualsp/rust-analyzer.lualsp/rust_analyzer.lualsp/ts_ls.lualsp/ty.lualua/config/autocmds.lualua/plugins/oil.lualua/utils/lsp.lualua/utils/vscode_treesitter.luascripts/install-tools.sh
💤 Files with no reviewable changes (2)
- lsp/basedpyright.lua
- lsp/rust_analyzer.lua
🚧 Files skipped from review as they are similar to previous changes (3)
- lua/plugins/oil.lua
- .auto/prompt.md
- lua/utils/vscode_treesitter.lua
| {"run":17,"commit":"1f26348","metric":0,"metrics":{"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":638},"status":"keep","description":"gSpace expand-only without flash labels","timestamp":1785800597846,"segment":0,"confidence":null,"asi":{"hypothesis":"g<Space> calls expand() only (no flash.treesitter labels); S keeps labeled select","metric_note":"compat_failures at floor 0; keep UX preference","user_request":"gSpace work but should only focus expand, no mark label like S","verification":"expand grew 30:9-14 → 30:5-14; uses expand not select"}} | ||
| {"run":18,"commit":"2cfb269","metric":0,"metrics":{"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":639},"status":"keep","description":"Load oil.nvim eagerly for directory BufEnter","timestamp":1785801123340,"segment":0,"confidence":null,"asi":{"hypothesis":"Set oil.nvim lazy=false so default_file_explorer owns directory BufEnter before first open","metric_note":"compat_failures at floor 0; keep oil timing fix","root_cause":"key-lazy oil can miss directory BufEnter; upstream recommends lazy=false","user_request":"Ensure oil init/keys fire early before BufEnter on directories","verification":"oil_loaded start; edit dir → ft=oil; dash_desc=Open parent directory (oil)"}} | ||
| {"run":19,"commit":"7a315a7","metric":0,"metrics":{"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":653},"status":"keep","description":"Global LspAttach + harden all-config LSP load check","timestamp":1785805208888,"segment":0,"confidence":null,"asi":{"hypothesis":"Global LspAttach applies shared keymaps to every server; remove rust_analyzer shim; harden fail_lsp to require every lsp/*.lua has cmd (LSP_ALL_OK)","metric_note":"compat_failures at floor 0; keep LSP completeness fix (stricter fail_lsp still green)","root_cause":"eslint/json/oxlint/tailwindcss lacked on_attach; harness only checked API presence","user_request":"Verify/fix all servers load on 0.13","verification":"all 12 remaining configs LOAD_OK + enable; fail_lsp=0 after LSP_ALL_OK assertion","supports":["treesitter","ai","lsp","miniai"]}} |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win
Emit explicit schema metadata for the new run record.
.auto/ideas.md documents schema_version 1 and distinguishes partial result records from complete run records. This new record still omits schema_version and an explicit check-set marker. Add those fields to every record type, or document and implement the implicit contract consistently.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In @.auto/log.jsonl around lines 19 - 21, Update the run records emitted in the
logging path to include explicit schema_version metadata and a check-set marker,
matching the schema_version 1 contract documented in .auto/ideas.md. Apply the
fields consistently to every record type, including partial result records, and
preserve the existing run metrics and metadata.
| local ok_var, attached = pcall(vim.api.nvim_buf_get_var, buffer, "_tiny_nvim_lsp_keymaps") | ||
| if ok_var and attached then | ||
| return | ||
| end | ||
| pcall(vim.api.nvim_buf_set_var, buffer, "_tiny_nvim_lsp_keymaps", true) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Files:"
git ls-files | rg '(^|/)lua/utils/lsp\.lua$|\.lua$' | sed -n '1,120p'
echo
echo "lua/utils/lsp.lua outline:"
ast-grep outline lua/utils/lsp.lua --view expanded || true
echo
echo "Relevant lua/utils/lsp.lua lines:"
cat -n lua/utils/lsp.lua | sed -n '1,140p'
echo
echo "Search for _tiny_nvim_lsp_keymaps and setup client mapping logic:"
rg -n "_tiny_nvim_lsp_keymaps|nvim_buf_get_var|nvim_buf_set_var|definitionProvider|setup.*client|client.*setup|on_attach|capabilities" -S lua || trueRepository: jellydn/tiny-nvim
Length of output: 8308
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Files:"
git ls-files | rg '(^|/)lua/utils/lsp\.lua$|\.lua$' | sed -n '1,160p'
echo
echo "lua/utils/lsp.lua outline:"
ast-grep outline lua/utils/lsp.lua --view expanded || true
echo
echo "Relevant lua/utils/lsp.lua lines:"
cat -n lua/utils/lsp.lua | sed -n '1,180p'
echo
echo "Search relevant symbols:"
rg -n "_tiny_nvim_lsp_keymaps|nvim_buf_get_var|nvim_buf_set_var|definitionProvider|capabilities|on_attach|setup.*client|client.*setup" -S lua || trueRepository: jellydn/tiny-nvim
Length of output: 9600
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "lua/config/autocmds.lua relevant lines:"
cat -n lua/config/autocmds.lua | sed -n '160,225p'
echo
echo "Python config relevant lines:"
cat -n lua/langs/python.lua | sed -n '1,220p'
echo
echo "Read-only simulation of capacity-dependent map selection for this code path:"
python3 - <<'PY'
default_keymaps = [
{ "keys": "<leader>ca", "has": None },
{ "keys": "<leader>.", "has": None },
{ "keys": "<leader>cA", "has": None },
{ "keys": "<leader>cr", "has": None },
{ "keys": "<leader>cf", "has": None },
{ "keys": "<leader>k", "has": "hoverProvider" },
{ "keys": "K", "has": "hoverProvider" },
{ "keys": "gd", "has": "definitionProvider" },
]
def maps_for_client(capabilities):
return [m["keys"] for m in default_keymaps if not m["has"] or capabilities.get(m["has"])]
client_no_definition = {"hoverProvider":True,"definitionProvider":False, "codeActionProvider":True, "codeLensProvider":True, "documentFormattingProvider":True}
client_with_definition = {"hoverProvider":True,"definitionProvider":True, "codeActionProvider":True, "codeLensProvider":True, "documentFormattingProvider":True}
order_a = [maps_for_client(client_no_definition), maps_for_client(client_with_definition)]
order_b = [maps_for_client(client_with_definition), maps_for_client(client_no_definition)]
print("order_no-definition_first =", order_a)
print("order_with-definition_first =", order_b)
print("gd_in_no-definition_first =", "gd" in maps_for_client(client_no_definition))
print("gd_in_with-definition_first =", "gd" in maps_for_client(client_with_definition))
print("gd_in_repeated_no-definition_after_with =", "gd" in maps_for_client(client_no_definition))
PYRepository: jellydn/tiny-nvim
Length of output: 3343
Do not mark the buffer complete before capability-dependent maps are installed.
This guards on the first client, so a second client can still be skipped. If the first client lacks definitionProvider, gd is never mapped when a later client supports it. Track installed keys per capability or remove the buffer-wide early return when keys are already installed.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@lua/utils/lsp.lua` around lines 27 - 31, Update the buffer keymap setup
around _tiny_nvim_lsp_keymaps so it does not return solely because an earlier
client marked the buffer complete. Track installation per capability-dependent
key, or otherwise continue checking each client’s capabilities, ensuring later
clients can install maps such as gd when they provide definitionProvider.
| for _, bin in ipairs(candidates) do | ||
| if vim.fn.executable(bin) == 1 then | ||
| local help = vim.fn.system { bin, "server", "--help" } | ||
| if type(help) == "string" and help:find("language server", 1, true) then | ||
| return { bin, "server" } | ||
| end | ||
| end | ||
| end | ||
| return { "ruff", "server" } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
ruff_bin="$(command -v ruff || true)"
if [[ -z "$ruff_bin" ]]; then
echo "No Ruff executable is on PATH."
exit 0
fi
if "$ruff_bin" server --help 2>&1 | grep -Fqi "language server"; then
echo "Compatible Ruff: $ruff_bin"
else
echo "Incompatible Ruff would be retried by the current fallback: $ruff_bin"
exit 1
fiRepository: jellydn/tiny-nvim
Length of output: 192
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Repo files matching lsp.lua:"
fd -a 'lsp\.lua$' . | sed 's#^\./##'
echo
echo "Outline for lua/utils/lsp.lua (if present):"
ast-grep outline lua/utils/lsp.lua 2>/dev/null || true
echo
echo "Relevant lines in lua/utils/lsp.lua:"
sed -n '1,220p' lua/utils/lsp.lua | nl -ba
echo
echo "Files matching ruff:"
fd -a 'ruff.*|.*ruff.*' lua . 2>/dev/null | sed 's#^\./##' | head -50
echo
echo "Search for lsp/detect or ruff startup:"
rg -n "detect_ruff|get_ruff|lsp/ruff|ruff|language server|server --help|executable\\(" -S .Repository: jellydn/tiny-nvim
Length of output: 377
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Relevant lines in lua/utils/lsp.lua:"
sed -n '1,220p' lua/utils/lsp.lua
echo
echo "Files matching ruff:"
find . \( -path './lua' -o -path './.git' \) -prune -o \
\( -iname '*ruff*' -o -path '*/lua/**/lsp/*' \) -print | sort
echo
echo "Search for detect_ruff/ruff startup:"
grep -RIn "detect_ruff\|get_ruff\|lsp/ruff|server --help|language server|executable\\(|start_ruff|ruff" . --exclude-dir=.git || trueRepository: jellydn/tiny-nvim
Length of output: 6511
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "lsp/ruff.lua:"
sed -n '1,240p' lsp/ruff.lua
echo
echo "ruff_cmd usages:"
grep -RIn "ruff_cmd\\|lsp/ruff\\|start_ruff\\|ruff" . --exclude-dir=.git
echo
echo "Behavioral probe: simulate M.ruff_cmd candidates with rejected ruff-candidates"
cat > /tmp/ruff_cmd_probe.lua <<'LUA'
local M = {}
function M.ruff_cmd(candidates_by_name, help_text)
local candidates = candidates_by_name
for _, bin in ipairs(candidates) do
if help_text[bin] then
help = help_text[bin]
if type(help) == "string" and help:find("language server", 1, true) then
return { bin, "server" }
end
end
end
return { "ruff", "server" }
end
return M
LUARepository: jellydn/tiny-nvim
Length of output: 3272
🌐 Web query:
Neovim vim.lsp.setup cmd function array server exits if command not executable language server
💡 Result:
In Neovim, if a language server command provided in the cmd array is not found or not executable, the LSP client will fail to start and typically report an error [1]. Current Neovim versions handle this by attempting to spawn the process using uv.spawn [2]. If the command fails to execute (e.g., file not found, permission denied), Neovim will report that the language server is either not installed, missing from the PATH, or not executable [1]. Key considerations for handling this behavior include: - Command Resolution: When cmd is a string array, Neovim treats the first element as the executable [3]. If it is not an absolute path, it is searched for in the system $PATH [3][4]. - Environment Variables: Neovim's built-in LSP client does not always automatically respect a custom PATH provided in cmd_env when checking for executability [5][6]. This often leads to "not found" errors even when the server is installed in a directory specified in your environment [5][2]. - Troubleshooting: - Verify if the command can be executed directly from your terminal shell [4][7]. - Use :LspInfo to check the status of configured servers [4][7]. Note that :LspInfo may sometimes report that a command is "not executable" incorrectly if it does not correctly account for your custom PATH or environment [5]. - If using relative paths or servers outside the standard PATH, provide the absolute path to the binary in your cmd configuration [8][7]. - On Windows, ensure that commands requiring a .cmd or .bat extension have the extension explicitly included if they are not being resolved automatically [2]. To avoid issues, ensure that your vim.lsp.start or lspconfig setup calls are properly guarded, often by placing them within a FileType autocmd or ftplugin to ensure they only attempt to start when relevant files are opened [9][10][4].
Citations:
- 1: The language server is either not installed, missing from PATH, or not executable. neovim/neovim#27602
- 2: append ".cmd" to command arg0 if it fails on Windows neovim/nvim-lspconfig#2130
- 3: https://github.com/neovim/neovim/blob/fcb43e8a/runtime/lua/vim/lsp/client.lua
- 4: https://github.com/neovim/nvim-lspconfig/blob/master/doc/lspconfig.txt
- 5: cmd_not_found should consider PATH in cmd_env neovim/nvim-lspconfig#1887
- 6: lsp: respect cmd_env when checking if servers are executable neovim/neovim#15648
- 7: https://github.com/neovim/nvim-lspconfig/blob/30a2b191/README.md
- 8: Can't start LSP server outside of
$PATH, even thoughcmd_cwdis provided. neovim/neovim#14072 - 9: https://neovim.io/doc/user/lsp/
- 10: https://github.com/neovim/neovim/blob/fcb43e8a/runtime/doc/lsp.txt
Do not retry a Ruff executable that M.ruff_cmd() rejects.
When M.ruff_cmd() rejects the only candidate, the fallback returns { "ruff", "server" }. Neovim resolves ruff from the same PATH, so the Ruff LSP starts with the unsupported binary and fails. Return an explicit unavailable result from M.ruff_cmd() and guard lsp/ruff.lua from starting.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@lua/utils/lsp.lua` around lines 137 - 145, Update M.ruff_cmd() to return an
explicit unavailable result when no validated executable is found instead of
falling back to { "ruff", "server" }. In lsp/ruff.lua, check that result before
starting the Ruff LSP and skip setup when unavailable, preventing Neovim from
retrying an unsupported PATH executable.
Source: Coding guidelines
Result: {"status":"keep","metric":0,"compat_failures":0,"fail_ai":0,"fail_binary":0,"fail_deprecated":0,"fail_fixture_lua":0,"fail_fixture_md":0,"fail_loadfile":0,"fail_lsp":0,"fail_messages":0,"fail_miniai":0,"fail_startup":0,"fail_treesitter":0,"fail_vim_loop":0,"startup_ms":645}
1de4bd4 to
e25a3b7
Compare
Summary
Migrate tiny-nvim to Neovim 0.13 while keeping treesitter, AI (sidekick), and native LSP working, then harden vscode-neovim / oil / flash UX and modernize the per-language LSP toolchain.
Core 0.13 compatibility
nvim-treesitter/nvim-treesitter-textobjects(main) so mini.ai treesitter textobjects work again (textobjects.scmno longer ships with core treesitter)vim.uvover deprecatedvim.looppcall+ lang membership).auto/compatibility harness (compat_failuresprimary metric)tree-sitterCLI via mise inscripts/install-tools.sh(parser compile needs it on 0.11+)NVIM_BIN/PATHnvim resolution; bash 3.2-safe warm-startup sort; narrow LSP env-noise filterBuilt-in dir browser / oil
nvim.direarly (vim.g.loaded_nvim_dir_plugin) — it mapped-to an in-buffer directory tree-(parent dir) and loads eagerly (lazy = false) sodefault_file_explorerwins directory BufEnter-reveals the current file in VS Code explorer (not a buffer tree)flash.nvim on 0.13 + vscode
utils.flash_hacks(upstream PR #496) and preload onnvim-0.13— Neovim #39485 moved search FFI globals intoSearch; without this,scrashes withsearch_match_linesdlsym errorS(treesitter): terminal uses flash labels; vscode paints letter marks viavscode.evalTextEditorDecorationType(utils.vscode_treesitter.select) because nvim virt_text overlays are unreliable thereg<Space>(and Ctrl+Space / C-@ / Nul / M-Space aliases): expand-only treesitter selection (no letter marks) — Ctrl+Space is often stolen by macOS Input Sources / Cursor Suggest, sog<Space>is the reliable primary chordgS/ visual shrink via the same helperModern LSP toolchain
ty(types) +ruff(lint/format); dropbasedpyright. Prefer uv/mise binaries over Homebrew stubsvtsls(ts_lskept as legacy override viavim.g.lsp_typescript_server)vim.g.lsp_js_linterorvim.g.lsp_on_demandsgopls(gofumpt/staticcheck/hints),rust-analyzer(clippy/procMacro),lua_ls(LuaJIT + workspace library)LspAttachapplies shared keymaps to every enabled server (covers configs that omiton_attach)lsp/*.luamust load withcmd(LSP_ALL_OK) + smoke client attach on temp fixtures (LSP_ATTACH_OK)Other polish
<leader>fwmaps invscode.luaWhy
On Neovim 0.13 / nvim-treesitter
main:textobjects.scmmoved tonvim-treesitter-textobjects→ mini.ai E5108nvim.dirhijacks-(especially painful in vscode-neovim)search_match_linesglobalsincremental_selectionis gone — expand-onlyg<Space>replaces labeled flash for that chordbasedpyrightstack was behind current Astral + vtsls practiceHow to use (after merge)
-Sg<Space>gSty+ruffvtsls+ one of biome/oxlint/eslint (auto)goplsrust-analyzerlua_lsOptional: restore literal Ctrl+Space in Cursor with a
vscode-neovim.sendkeybinding (see.auto/ideas.md).Validation
./.auto/checks.sh→ pass./.auto/measure.sh→METRIC compat_failures=0(includingfail_miniai=0,fail_treesitter=0,fail_lsp=0/ attach smoke)afon Lua; oil on:e .; flashs/S;g<Space>expand; vscode-/S/g<Space>; open a Python/TS buffer and confirm ty/vtsls + detected linterChecklist
.auto/measure.sh+ fixtures + LSP attach smoke).auto/prompt.md, plan notes under.auto/)-no longer opens builtin dir tree; preferg<Space>over Ctrl+Space for expand; Python uses ty not basedpyright; TS defaults to vtsls; JS lint is marker-driven (not always biome+oxlint)Follow-ups (deferred)
lua/utils/flash_hacks.luaonce folke/flash.nvim merges PR #496lsp/ts_ls.luaonce no projects override to legacy typescript-language-serveran/inalongsideg<Space>~/.local/binis on PATH so uv-installedty/ruffwin over Homebrew stubs