Skip to content

refactor: migrate to built-in treesitter API and extract surround module#13

Closed
fecet wants to merge 7 commits intomasterfrom
main
Closed

refactor: migrate to built-in treesitter API and extract surround module#13
fecet wants to merge 7 commits intomasterfrom
main

Conversation

@fecet
Copy link
Copy Markdown
Member

@fecet fecet commented Mar 24, 2026

Summary

  • Remove nvim-treesitter dependency, migrate to built-in vim.treesitter API
  • Extract surround detection into surround.lua using TS node structure (anonymous children as delimiters) instead of text-based regex matching
  • Fix selection expansion across injected language trees (e.g. JS inside HTML)
  • Add bounds checking and coordinate conversion fixes

State Protocol: Pluggable Checkpoint

Current selection state is managed by two module-level tables:

selections[buf]  -- stack of selections (TSNode | {srow,scol,erow,ecol})
nodes_all[buf]   -- stack of TSNode references

This works but couples the state representation tightly to the expansion algorithm. With neovim/neovim@72d3a57 landing built-in vim.treesitter._select (providing an/in/]n/[n default 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":

---@class wildfire.Checkpoint
---@field save fun(self, buf: integer, node: TSNode, range: table)
---@field restore fun(self, buf: integer): TSNode|table|nil
---@field reset fun(self, buf: integer)
---@field current fun(self, buf: integer): TSNode|table|nil

This allows swapping the backing implementation:

  • Built-in backend — delegate to vim.treesitter._select history when available (Neovim nightly+)
  • Custom backend — current stack-based approach as fallback for stable Neovim

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
  • Repeated <CR> expands through parent nodes, selecting inner content first for surround nodes ((), {}, [], <>)
  • <BS> shrinks back to previous selection
  • Count prefix works (3<CR> jumps 3 levels)
  • Selection crosses injected language boundaries (e.g. <script> in HTML)
  • Empty surrounds ((), {}) are handled without error
  • No nvim-treesitter required at runtime

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

2 participants