Conversation
- Remove dependency on nvim-treesitter.ts_utils module - Replace ts_utils.get_node_at_cursor() with vim.treesitter.get_node() - Replace ts_utils.get_vim_range() with vim.treesitter.get_node_range() - Replace ts_utils.get_node_text() with vim.treesitter.get_node_text() - Add proper coordinate conversion from 0-based to 1-based indexing - Ensure compatibility with modern nvim-treesitter versions
The previous migration incorrectly added +1 to end_col when converting from treesitter's 0-based exclusive indexing to vim's 1-based inclusive indexing. This caused selections to include an extra character on the right side. The correct conversion is: - start_row, start_col, end_row: 0-based -> 1-based (add +1) - end_col: 0-based exclusive == 1-based inclusive (no change needed) This fixes the bug where selecting text inside brackets/quotes would incorrectly include the closing bracket/quote character.
- Replace deprecated parsers.get_parser() with vim.treesitter.get_parser(buf) - Add buffer/column bounds validation in unsurround_coordinates() - Add cursor position clamping in update_selection() - Use pcall for safe API calls and graceful error handling - Fix E5108 crashes on blank lines and unsupported filetypes
Use utils.get_range() instead of duplicating node-range conversions and simplify selection_mode normalization.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a60bd4e9e2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if start_row < 1 or end_row < 1 or start_row > line_count or end_row > line_count then | ||
| -- Invalid row range, cannot update selection |
There was a problem hiding this comment.
Allow selecting nodes that end at EOF
This guard rejects valid Tree-sitter ranges at file end because ranges are end-exclusive before conversion. For nodes that end at EOF (common when the buffer has a trailing newline), end_row becomes line_count + 1 after +1, so update_selection returns early and incremental expansion silently stops before the outer node can be selected; meanwhile callers still push that node into history, which can desynchronize selection state from what is visible.
Useful? React with 👍 / 👎.
| local last = node:child(child_count - 1) | ||
|
|
||
| -- Anonymous nodes are delimiters | ||
| return first and last and not first:named() and not last:named() |
There was a problem hiding this comment.
Limit surround heuristic to bracket delimiters
This heuristic classifies any node with anonymous first/last children as a surround, which incorrectly matches many non-delimiter constructs (for example statement nodes like return x; in JS grammars). In those cases unsurround_coordinates treats keywords/punctuation as wrappers and can introduce unintended intermediate selections, changing expansion behavior beyond bracket-like surrounds that the plugin previously targeted.
Useful? React with 👍 / 👎.
Summary
nvim-treesitterdependency, migrate to built-invim.treesitterAPIsurround.luausing TS node structure (anonymous children as delimiters) instead of text-based regex matchingState Protocol: Pluggable Checkpoint
Current selection state is managed by two module-level tables:
This works but couples the state representation tightly to the expansion algorithm. With neovim/neovim@72d3a57 landing built-in
vim.treesitter._select(providingan/in/]n/[ndefault mappings), Neovim will ship its own incremental selection with its own history/checkpoint mechanism.To prepare for this, the next step is to define a checkpoint protocol — an interface that decouples "what to remember" from "how to remember it":
This allows swapping the backing implementation:
vim.treesitter._selecthistory when available (Neovim nightly+)With this separation, wildfire's unique value (surround-aware inner selection) becomes a thin layer on top of whichever checkpoint backend is active, rather than reimplementing the full node traversal + injection handling that Neovim now ships.
Test plan
<CR>on cursor starts selection at TS node under cursor<CR>expands through parent nodes, selecting inner content first for surround nodes ((),{},[],<>)<BS>shrinks back to previous selection3<CR>jumps 3 levels)<script>in HTML)(),{}) are handled without errornvim-treesitterrequired at runtime