Migrate nvim-treesitter to main branch
The master branch is archived and its parsers no longer match nvim
head. Main is a smaller rewrite with no `configs.setup`; parsers
install via `.install()`, highlights move to a native FileType
autocmd, incremental selection becomes a small custom module, and
textobjects-main rebinds via per-module require calls. The setup
moves to its own treesitter.fnl since the new shape is sizeable.
Assisted-by: Claude Opus 4.7 via Claude Code
diff --git a/.config/nvim/fnl/init.fnl b/.config/nvim/fnl/init.fnl
index 71cafe4f..b0201a7d 100644
--- a/.config/nvim/fnl/init.fnl
+++ b/.config/nvim/fnl/init.fnl
@@ -131,9 +131,11 @@
:version :v3.9.1}
{:src "https://github.com/neovim/nvim-lspconfig.git"
:version (vim.version.range :v2.8.0)}
- "https://github.com/nvim-treesitter/nvim-treesitter.git"
+ {:src "https://github.com/nvim-treesitter/nvim-treesitter.git"
+ :version :main}
"https://github.com/nvim-treesitter/nvim-treesitter-context.git"
- "https://github.com/nvim-treesitter/nvim-treesitter-textobjects.git"
+ {:src "https://github.com/nvim-treesitter/nvim-treesitter-textobjects.git"
+ :version :main}
;; here for completeness, but actually added in init.lua for bootstrapping purposes
; "https://github.com/rktjmp/hotpot.nvim.git"
"https://github.com/suy/vim-context-commentstring.git"
@@ -197,72 +199,7 @@
(set vim.g.netrw_home "~/.nvim_tmp")
;;; treesitter
-(let [{: treesitter} vim
- {: setup} (require :nvim-treesitter.configs)]
- (setup {:ensure_installed [:fennel
- :hcl
- :lua
- :python
- :query
- :ruby
- :rust
- :terraform
- :typescript
- :yaml]
- :sync_install false
- :highlight {:enable true :additional_vim_regex_highlighting false}
- ;; disabling since this is super annoying in Ruby
- ; :indent {:enable true}
- :incremental_selection {:enable true
- :keymaps {:init_selection :gnn
- :node_incremental :grn
- :scope_incremental :grc
- :node_decremental :grm}}
- :textobjects {:move {:enable true
- :set_jumps true
- :goto_next_start {"]a" "@parameter.inner"
- "]b" "@block.outer"
- "]c" "@class.inner"
- "]f" "@function.outer"}
- :goto_next_end {"]A" "@parameter.inner"
- "]B" "@block.outer"
- "]C" "@class.outer"
- "]F" "@function.outer"}
- :goto_previous_start {"[a" "@parameter.inner"
- "[b" "@block.outer"
- "[c" "@class.outer"
- "[f" "@function.outer"}
- :goto_previous_end {"[A" "@parameter.inner"
- "[B" "@block.outer"
- "[C" "@class.outer"
- "[F" "@function.outer"}}
- :select {:enable true
- :lookahead true
- :keymaps {:af "@function.outer"
- :if "@function.inner"
- :ac "@class.outer"
- :ic "@class.inner"
- :ab "@block.outer"
- :ib "@block.inner"
- :aa "@parameter.outer"
- :ia "@parameter.inner
- "}}
- :swap {:enable true
- :swap_next {:<leader>a "@parameter.inner"}
- :swap_previous {:<leader>A "@parameter.inner"}}}})
- (treesitter.language.register :yaml :yaml.ansible)
- (treesitter.query.set :python :folds "[
- (function_definition)
- (class_definition)
- (block)
-] @fold
-[
- (import_statement)
- (import_from_statement)
-]+ @fold"))
-
-(let [{: setup} (require :treesitter-context)]
- (setup))
+(require :treesitter)
;; https://neovim.io/doc/user/lsp.html#vim.lsp.foldexpr()
(set vim.o.foldmethod :expr)
diff --git a/.config/nvim/fnl/treesitter.fnl b/.config/nvim/fnl/treesitter.fnl
new file mode 100644
index 00000000..a473f95d
--- /dev/null
+++ b/.config/nvim/fnl/treesitter.fnl
@@ -0,0 +1,120 @@
+(local {:api {:nvim_buf_set_mark nvim-buf-set-mark
+ :nvim_create_autocmd nvim-create-autocmd
+ :nvim_get_current_buf nvim-get-current-buf}
+ : keymap
+ : treesitter} vim)
+
+;;; parsers
+;; Async install at startup; subsequent calls no-op for already-installed parsers.
+(let [ts (require :nvim-treesitter)]
+ (ts.install [:fennel :hcl :lua :python :query :ruby :rust :terraform
+ :typescript :yaml]))
+
+;;; highlighting
+;; Native treesitter highlight per filetype with a parser; pcall covers filetypes without one.
+(nvim-create-autocmd :FileType
+ {:callback #(pcall treesitter.start $1.buf)})
+
+;;; custom queries
+(treesitter.language.register :yaml :yaml.ansible)
+(treesitter.query.set :python :folds "[
+ (function_definition)
+ (class_definition)
+ (block)
+] @fold
+[
+ (import_statement)
+ (import_from_statement)
+]+ @fold")
+
+;;; incremental selection
+;; Replaces the `incremental_selection` module from nvim-treesitter master.
+;; Maintains a per-buffer stack of nodes; each expansion pushes the parent.
+(let [stacks {}
+ get-stack #(or (. stacks $1) [])
+ select-node (fn [node]
+ (let [(srow scol erow ecol) (node:range)]
+ (nvim-buf-set-mark 0 :< (+ srow 1) scol {})
+ (nvim-buf-set-mark 0 :> (+ erow 1)
+ (math.max (- ecol 1) 0) {})
+ (vim.cmd "normal! gv")))
+ push (fn [bufnr node]
+ (let [stack (get-stack bufnr)]
+ (table.insert stack node)
+ (tset stacks bufnr stack)
+ (select-node node)))
+ expand (fn []
+ (let [bufnr (nvim-get-current-buf)
+ stack (get-stack bufnr)
+ current (. stack (length stack))
+ parent (and current (current:parent))]
+ (when parent (push bufnr parent))))
+ shrink (fn []
+ (let [bufnr (nvim-get-current-buf)
+ stack (get-stack bufnr)]
+ (when (> (length stack) 1)
+ (table.remove stack)
+ (tset stacks bufnr stack)
+ (select-node (. stack (length stack))))))]
+ (keymap.set :n :gnn
+ #(let [bufnr (nvim-get-current-buf)
+ node (treesitter.get_node)]
+ (when node
+ (tset stacks bufnr [])
+ (push bufnr node))))
+ (keymap.set :x :grn expand)
+ (keymap.set :x :grc expand)
+ (keymap.set :x :grm shrink))
+
+;;; textobjects (nvim-treesitter-textobjects main branch)
+(let [{: setup} (require :nvim-treesitter-textobjects)
+ ts-select (require :nvim-treesitter-textobjects.select)
+ ts-swap (require :nvim-treesitter-textobjects.swap)
+ ts-move (require :nvim-treesitter-textobjects.move)
+ bind-each (fn [modes specs action]
+ (each [_ [lhs query] (ipairs specs)]
+ (keymap.set modes lhs #(action query :textobjects))))]
+ (setup {:select {:lookahead true} :move {:set_jumps true}})
+
+ (bind-each [:x :o]
+ [[:af "@function.outer"]
+ [:if "@function.inner"]
+ [:ac "@class.outer"]
+ [:ic "@class.inner"]
+ [:ab "@block.outer"]
+ [:ib "@block.inner"]
+ [:aa "@parameter.outer"]
+ [:ia "@parameter.inner"]]
+ ts-select.select_textobject)
+
+ (keymap.set :n :<leader>a #(ts-swap.swap_next "@parameter.inner"))
+ (keymap.set :n :<leader>A #(ts-swap.swap_previous "@parameter.inner"))
+
+ (bind-each [:n :x :o]
+ [["]a" "@parameter.inner"]
+ ["]b" "@block.outer"]
+ ["]c" "@class.inner"]
+ ["]f" "@function.outer"]]
+ ts-move.goto_next_start)
+ (bind-each [:n :x :o]
+ [["]A" "@parameter.inner"]
+ ["]B" "@block.outer"]
+ ["]C" "@class.outer"]
+ ["]F" "@function.outer"]]
+ ts-move.goto_next_end)
+ (bind-each [:n :x :o]
+ [["[a" "@parameter.inner"]
+ ["[b" "@block.outer"]
+ ["[c" "@class.outer"]
+ ["[f" "@function.outer"]]
+ ts-move.goto_previous_start)
+ (bind-each [:n :x :o]
+ [["[A" "@parameter.inner"]
+ ["[B" "@block.outer"]
+ ["[C" "@class.outer"]
+ ["[F" "@function.outer"]]
+ ts-move.goto_previous_end))
+
+;;; treesitter-context
+(let [{: setup} (require :treesitter-context)]
+ (setup))
diff --git a/.config/nvim/nvim-pack-lock.json b/.config/nvim/nvim-pack-lock.json
index 2cf49c57..f6946a86 100644
--- a/.config/nvim/nvim-pack-lock.json
+++ b/.config/nvim/nvim-pack-lock.json
@@ -35,16 +35,18 @@
"version": "2.8.0 - 2.8.0"
},
"nvim-treesitter": {
- "rev": "cf12346a3414fa1b06af75c79faebe7f76df080a",
- "src": "https://github.com/nvim-treesitter/nvim-treesitter.git"
+ "rev": "4916d6592ede8c07973490d9322f187e07dfefac",
+ "src": "https://github.com/nvim-treesitter/nvim-treesitter.git",
+ "version": "'main'"
},
"nvim-treesitter-context": {
"rev": "b0c45cefe2c8f7b55fc46f34e563bc428ef99636",
"src": "https://github.com/nvim-treesitter/nvim-treesitter-context.git"
},
"nvim-treesitter-textobjects": {
- "rev": "71385f1",
- "src": "https://github.com/nvim-treesitter/nvim-treesitter-textobjects.git"
+ "rev": "851e865342e5a4cb1ae23d31caf6e991e1c99f1e",
+ "src": "https://github.com/nvim-treesitter/nvim-treesitter-textobjects.git",
+ "version": "'main'"
},
"vim-abolish": {
"rev": "dcbfe06",