Skip to content

fix(nvim): migrate config to Neovim 0.13 - #8

Open
jellydn wants to merge 24 commits into
mainfrom
autoresearch/nvim-0.13-migration-2026-08-03
Open

fix(nvim): migrate config to Neovim 0.13#8
jellydn wants to merge 24 commits into
mainfrom
autoresearch/nvim-0.13-migration-2026-08-03

Conversation

@jellydn

@jellydn jellydn commented Aug 3, 2026

Copy link
Copy Markdown
Owner

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

  • Add nvim-treesitter/nvim-treesitter-textobjects (main) so mini.ai treesitter textobjects work again (textobjects.scm no longer ships with core treesitter)
  • Prefer vim.uv over deprecated vim.loop
  • Harden treesitter FileType start (pcall + lang membership)
  • Add frozen .auto/ compatibility harness (compat_failures primary metric)
  • Install/wire tree-sitter CLI via mise in scripts/install-tools.sh (parser compile needs it on 0.11+)
  • Portable harness: NVIM_BIN / PATH nvim resolution; bash 3.2-safe warm-startup sort; narrow LSP env-noise filter

Built-in dir browser / oil

  • Disable Neovim 0.13 nvim.dir early (vim.g.loaded_nvim_dir_plugin) — it mapped - to an in-buffer directory tree
  • Terminal: oil owns - (parent dir) and loads eagerly (lazy = false) so default_file_explorer wins directory BufEnter
  • vscode-neovim: - reveals the current file in VS Code explorer (not a buffer tree)

flash.nvim on 0.13 + vscode

  • Vendor utils.flash_hacks (upstream PR #496) and preload on nvim-0.13 — Neovim #39485 moved search FFI globals into Search; without this, s crashes with search_match_lines dlsym error
  • Keep flash enabled under vscode-neovim
  • S (treesitter): terminal uses flash labels; vscode paints letter marks via vscode.eval TextEditorDecorationType (utils.vscode_treesitter.select) because nvim virt_text overlays are unreliable there
  • g<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, so g<Space> is the reliable primary chord
  • gS / visual shrink via the same helper

Modern LSP toolchain

  • Python: Astral stack — ty (types) + ruff (lint/format); drop basedpyright. Prefer uv/mise binaries over Homebrew stubs
  • TypeScript/JS: default vtsls (ts_ls kept as legacy override via vim.g.lsp_typescript_server)
  • JS lint: smart detect one of biome → oxlint → eslint from project markers (no blanket eslint autostart). Override with vim.g.lsp_js_linter or vim.g.lsp_on_demands
  • Go / Rust / Lua: tightened gopls (gofumpt/staticcheck/hints), rust-analyzer (clippy/procMacro), lua_ls (LuaJIT + workspace library)
  • Global LspAttach applies shared keymaps to every enabled server (covers configs that omit on_attach)
  • Harness: every lsp/*.lua must load with cmd (LSP_ALL_OK) + smoke client attach on temp fixtures (LSP_ATTACH_OK)

Other polish

  • Clean duplicate <leader>fw maps in vscode.lua
  • CodeRabbit review fixes (UTF-16 columns for vscode decorations, install-tools tree-sitter fallthrough, docs/ideas clarifications)

Why

On Neovim 0.13 / nvim-treesitter main:

  • textobjects.scm moved to nvim-treesitter-textobjects → mini.ai E5108
  • Built-in nvim.dir hijacks - (especially painful in vscode-neovim)
  • flash.nvim FFI still reads removed search_match_lines globals
  • treesitter incremental_selection is gone — expand-only g<Space> replaces labeled flash for that chord
  • Default TS/basedpyright stack was behind current Astral + vtsls practice

How to use (after merge)

Chord Terminal vscode-neovim
- oil parent dir reveal in VS Code explorer
S flash treesitter labels labeled select via VS Code decorations
g<Space> expand treesitter parents (no labels) same
gS shrink (visual helper) shrink treesitter selection
Language Default LSP
Python ty + ruff
TypeScript/JS vtsls + one of biome/oxlint/eslint (auto)
Go gopls
Rust rust-analyzer
Lua lua_ls

Optional: restore literal Ctrl+Space in Cursor with a vscode-neovim.send keybinding (see .auto/ideas.md).

Validation

  • ./.auto/checks.sh → pass
  • ./.auto/measure.shMETRIC compat_failures=0 (including fail_miniai=0, fail_treesitter=0, fail_lsp=0 / attach smoke)
  • Manual: mini.ai af on Lua; oil on :e .; flash s/S; g<Space> expand; vscode - / S / g<Space>; open a Python/TS buffer and confirm ty/vtsls + detected linter

Checklist

  • Tests added or updated (.auto/measure.sh + fixtures + LSP attach smoke)
  • Documentation updated (README, .auto/prompt.md, plan notes under .auto/)
  • Breaking / behavior notes: - no longer opens builtin dir tree; prefer g<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)

  • Drop lua/utils/flash_hacks.lua once folke/flash.nvim merges PR #496
  • Drop lsp/ts_ls.lua once no projects override to legacy typescript-language-server
  • Document Neovim 0.13 visual an/in alongside g<Space>
  • Ensure ~/.local/bin is on PATH so uv-installed ty/ruff win over Homebrew stubs

jellydn and others added 3 commits August 3, 2026 23:12
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>
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

The 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.

Changes

Neovim 0.13 compatibility

Layer / File(s) Summary
Compatibility scope and metrics
.auto/config.json, .auto/prompt.md, .auto/ideas.md, .auto/log.jsonl
Defines migration constraints, metrics, deferred work, and recorded compatibility findings.
Runtime APIs and LSP configuration
init.lua, lua/langs/markdown.lua, lua/plugins/extra/codecompanion.lua, lua/config/autocmds.lua, lua/utils/lsp.lua, lsp/*, README.md
Replaces deprecated APIs, changes TypeScript and Python LSP defaults, adds ty, resolves managed tool commands, expands server settings, and prevents duplicate attach mappings.
Treesitter and editor integration
lua/plugins/ui.lua, lua/plugins/coding.lua, lua/plugins/flash.lua, lua/utils/flash_hacks.lua, lua/utils/vscode_treesitter.lua, lua/plugins/vscode.lua, lua/config/keymaps.lua, lua/plugins/oil.lua, lua/config/options.lua, lazy-lock.json, scripts/install-tools.sh
Updates Treesitter setup, adds textobject support, implements Flash compatibility, adds Treesitter selection controls, changes directory navigation, refreshes locks, and installs required tools.
Compatibility validation and measurement
.auto/checks.sh, .auto/measure.sh, .auto/fixtures/*
Adds syntax, startup, API, integration, Lua loading, fixture, LSP, mini.ai, and warm-start checks with compatibility metrics.

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
Loading

Poem

A rabbit checks each Lua line,
While Treesitter nodes align.
vim.uv hops through the code,
LSP servers share the load,
And startup metrics shine.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 59.26% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: migrating the Neovim configuration to Neovim 0.13.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch autoresearch/nvim-0.13-migration-2026-08-03

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@jellydn
jellydn marked this pull request as ready for review August 3, 2026 15:56

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
lua/plugins/ui.lua (1)

371-382: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Explicit 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 computes lang for the membership check at line 379, but line 382 does not reuse it. Pass ev.buf and lang explicitly, matching the pattern that Neovim's own documentation and the nvim-treesitter README use in FileType autocmd examples.

Separately, opts (line 372) still contains ensure_installed, a field the new nvim-treesitter main-branch setup() no longer recognizes (installation moved to a separate .install() call, already used at line 374). Passing it into TS.setup(opts) most likely has no effect, but it can mislead readers into thinking setup() 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-treesitter main branch's setup() tolerates or ignores unrecognized keys such as ensure_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

📥 Commits

Reviewing files that changed from the base of the PR and between b8a12d5 and c16e33f.

📒 Files selected for processing (12)
  • .auto/checks.sh
  • .auto/config.json
  • .auto/fixtures/sample.lua
  • .auto/fixtures/sample.md
  • .auto/measure.sh
  • .auto/prompt.md
  • init.lua
  • lazy-lock.json
  • lua/langs/markdown.lua
  • lua/plugins/coding.lua
  • lua/plugins/extra/codecompanion.lua
  • lua/plugins/ui.lua

Comment thread .auto/measure.sh Outdated
Comment thread .auto/measure.sh
Comment thread .auto/prompt.md Outdated
Comment thread .auto/prompt.md
@changeset-bot

changeset-bot Bot commented Aug 3, 2026

Copy link
Copy Markdown

⚠️ No Changeset found

Latest commit: e25a3b7

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@jellydn
jellydn force-pushed the autoresearch/nvim-0.13-migration-2026-08-03 branch from c57b948 to c16e33f Compare August 3, 2026 16:47
jellydn added 16 commits August 4, 2026 01:04
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}

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
lua/utils/vscode_treesitter.lua (1)

129-129: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Omit parentheses for single-string require calls.

  • lua/utils/vscode_treesitter.lua#L129-L129: Change require("vscode") to require "vscode".
  • lua/utils/vscode_treesitter.lua#L152-L152: Change require("vscode") to require "vscode".
  • lua/plugins/flash.lua#L11-L13: Change require("utils.vscode_treesitter") to require "utils.vscode_treesitter".
  • lua/plugins/flash.lua#L35-L40: Change both single-string require(...) calls to the no-parentheses form.
  • lua/config/keymaps.lua#L40-L48: Change both single-string require(...) calls to the no-parentheses form.
  • lua/plugins/vscode.lua#L99-L113: Change both single-string require(...) calls to the no-parentheses form.
  • lua/plugins/oil.lua#L105-L111: Change require("oil") to require "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 win

Add 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 aggregate compat_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

📥 Commits

Reviewing files that changed from the base of the PR and between c16e33f and 6741ec3.

📒 Files selected for processing (11)
  • .auto/ideas.md
  • .auto/log.jsonl
  • lua/config/keymaps.lua
  • lua/config/options.lua
  • lua/plugins/flash.lua
  • lua/plugins/oil.lua
  • lua/plugins/ui.lua
  • lua/plugins/vscode.lua
  • lua/utils/flash_hacks.lua
  • lua/utils/vscode_treesitter.lua
  • scripts/install-tools.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • lua/plugins/ui.lua

Comment thread .auto/ideas.md Outdated
Comment thread .auto/log.jsonl
Comment on lines +1 to +3
{"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"}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ 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)
PY

Repository: 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)
PY

Repository: 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.

Comment thread lua/utils/vscode_treesitter.lua
Comment thread scripts/install-tools.sh
@jellydn

jellydn commented Aug 4, 2026

Copy link
Copy Markdown
Owner Author

Addressed CodeRabbit review comments in the latest commit:

  • Portable NVIM (.auto/measure.sh, .auto/checks.sh, .auto/prompt.md): use NVIM_BIN or nvim from PATH
  • Startup sort (.auto/measure.sh): portable while read instead of unquoted array split (bash 3.2-safe)
  • LSP noise (.auto/measure.sh + prompt): named ENV_LSP_NOISE signatures; clarify fail_lsp is API/config presence only
  • vscode labels (lua/utils/vscode_treesitter.lua): convert byte columns → UTF-16 for VS Code decorations
  • tree-sitter install (scripts/install-tools.sh): fall through mise → cargo → npm on failure
  • ideas.md / log schema: clarify an/in status and document log.jsonl record shapes

Skipped (not actionable for this repo):

  • CodeRabbit walkthrough comment
  • Changeset bot (config repo, no package version bump)

jellydn added a commit that referenced this pull request Aug 4, 2026
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>
jellydn and others added 2 commits August 4, 2026 09:37
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>
jellydn added 2 commits August 4, 2026 09:37
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}
@jellydn
jellydn force-pushed the autoresearch/nvim-0.13-migration-2026-08-03 branch from aa744b6 to 2e6da6a Compare August 4, 2026 01:38

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
init.lua (1)

36-42: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Rename the LSP mapping table to PascalCase.

lsp_by_ft is a Lua table. Rename it to LspByFt and update its local references.

As per coding guidelines, “Use PascalCase for 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 win

Use the required require call style.

Bind the module with local lsp_utils = require "utils.lsp". Then call lsp_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

📥 Commits

Reviewing files that changed from the base of the PR and between 6741ec3 and 2e6da6a.

📒 Files selected for processing (20)
  • .auto/checks.sh
  • .auto/ideas.md
  • .auto/log.jsonl
  • .auto/measure.sh
  • .auto/prompt.md
  • README.md
  • init.lua
  • lsp/basedpyright.lua
  • lsp/gopls.lua
  • lsp/lua_ls.lua
  • lsp/ruff.lua
  • lsp/rust-analyzer.lua
  • lsp/rust_analyzer.lua
  • lsp/ts_ls.lua
  • lsp/ty.lua
  • lua/config/autocmds.lua
  • lua/plugins/oil.lua
  • lua/utils/lsp.lua
  • lua/utils/vscode_treesitter.lua
  • scripts/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

Comment thread .auto/log.jsonl
Comment on lines +19 to +21
{"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"]}}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ 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.

Comment thread lua/utils/lsp.lua
Comment on lines +27 to +31
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)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 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 || true

Repository: 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 || true

Repository: 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))
PY

Repository: 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.

Comment thread lua/utils/lsp.lua
Comment on lines +137 to +145
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" }

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 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
fi

Repository: 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 || true

Repository: 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
LUA

Repository: 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:


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}
@jellydn
jellydn force-pushed the autoresearch/nvim-0.13-migration-2026-08-03 branch from 1de4bd4 to e25a3b7 Compare August 4, 2026 01:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant