Skip to content

fix(move): no-op when buffer has no treesitter parser (#883) - #903

Open
simonyang08 wants to merge 1 commit into
nvim-treesitter:mainfrom
simonyang08:codex/tso-883-no-parser-move
Open

simonyang08 wants to merge 1 commit into
nvim-treesitter:mainfrom
simonyang08:codex/tso-883-no-parser-move

Conversation

@simonyang08

Copy link
Copy Markdown

Fixes #883.

Movement functions (goto_next_start, goto_next_end, goto_previous_start, goto_previous_end, goto_next, goto_previous, and the repeatable_move wrappers) raised a Lua error on buffers without an attached treesitter parser:

E5108: .../move.lua:86: attempt to perform arithmetic on local 'score' (a nil value)
E5108: .../move.lua:142: attempt to compare two nil values

Root cause

shared.find_best_range() returned an empty table ({}) when no parser was attached. An empty table is truthy in Lua, so move.lua proceeded to call scoring_function({}) and filter_function({}), dereferencing nil fields.

select_textobject was already silent because best_range_at_point() returns nil when its input list is empty — the asymmetry is purely on the find_best_range side.

Fix

Make find_best_range() return nil (matching its annotated return type Range6?) instead of {} when the parser is missing. The existing if current_range then guard in move.lua then correctly skips the iteration, and goto_node(nil, …) already no-ops in that case.

Test

New tests/move/no_parser_spec.lua: renders a scratch buffer with no filetype/parser and asserts every movement entry point is a silent no-op. The spec fails on main (9 of the calls raise the two error shapes from the issue) and passes with the fix.

Note: on buffers whose filetype maps to a registered but uninstalled parser, vim.treesitter.get_parser itself can still throw — that is core behavior outside this fix.

stylua clean; full local suite not run end-to-end (the bundled nvim-treesitter install script fails in this environment, unrelated to this change) — CI will exercise it.

…r#883)

Movement functions (goto_next_start/end, goto_previous_start/end,
goto_next, goto_previous, and the repeatable wrappers) raised a Lua
error on buffers without an attached treesitter parser:

  E5108: .../move.lua:86: attempt to perform arithmetic on local 'score'
    (a nil value)
  E5108: .../move.lua:142: attempt to compare two nil values

Root cause: shared.find_best_range() returned an empty table ({}) when
no parser was attached for the buffer. The empty table is truthy in
Lua, so move.lua proceeded to call scoring_function({}) and
filter_function({}) on it, dereferencing nil fields.

Selection textobjects (select_textobject) already handled this case
silently because best_range_at_point() returns nil when its input list
is empty.

Fix: have find_best_range() return nil (matching its annotated
return type Range6?) instead of {} when the parser is missing, so the
existing 'if current_range then' guard in move.lua correctly skips the
iteration and goto_node() is invoked with nil (which it already
handles as a no-op).

Verified with scripts/repro_883.lua:
  - before fix: 9/10 entry points error
  - after fix:  10/10 entry points return silently
  - parser-present path unaffected: move.goto_next_start on a C buffer
    still jumps to the function definition row.

Fixes nvim-treesitter#883

Signed-off-by: simonyang08 <ppt5928@gmail.com>
@simonyang08
simonyang08 marked this pull request as ready for review October 1, 2026 01:18
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.

textobjects.move errors when no Treesitter parser is available (should no-op like select)

2 participants