commit 72ed99319dd662f0e35b58e888b57f98ac3b3eec
parent 40139738eb479d0913ec6ce751ca5adfa50ad8c3
Author: Dmytro Soltys <soap@slotos.net>
Date: Mon, 27 Nov 2023 13:34:32 +0100
fix(treesitter): don't invalidate parser when discovering injections
When parsing with a range, languagetree looks up injections and adds
them if needed. This explicitly invalidates parser, making `is_valid`
report `false` both when including and excluding children.
This is an attempt to describe desired behaviour of `is_valid` in tests,
with what ended up being a single line change to satisfy them.
Diffstat:
2 files changed, 117 insertions(+), 2 deletions(-)
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
@@ -508,7 +508,6 @@ function LanguageTree:add_child(lang)
end
self._children[lang] = child
- self:invalidate()
self:_do_callback('child_added', self._children[lang])
return self._children[lang]
@@ -524,7 +523,6 @@ function LanguageTree:remove_child(lang)
if child then
self._children[lang] = nil
child:destroy()
- self:invalidate()
self:_do_callback('child_removed', child)
end
end
diff --git a/test/functional/treesitter/parser_spec.lua b/test/functional/treesitter/parser_spec.lua
@@ -1095,4 +1095,121 @@ int x = INT_MAX;
' ^',
'((identifier) @id \n(#eq? @id\n@ok.capture\n))')
end)
+
+ describe('is_valid()', function()
+ before_each(function()
+ insert(dedent[[
+ Treesitter integration *treesitter*
+
+ Nvim integrates the `tree-sitter` library for incremental parsing of buffers:
+ https://tree-sitter.github.io/tree-sitter/
+
+ ]])
+
+ feed(':set ft=help<cr>')
+
+ exec_lua [[
+ vim.treesitter.get_parser(0, "vimdoc", {
+ injections = {
+ vimdoc = "((codeblock (language) @injection.language (code) @injection.content) (#set! injection.include-children))"
+ }
+ })
+ ]]
+ end)
+
+ it('is valid excluding, invalid including children initially', function()
+ eq(true, exec_lua('return vim.treesitter.get_parser():is_valid(true)'))
+ eq(false, exec_lua('return vim.treesitter.get_parser():is_valid()'))
+ end)
+
+ it('is fully valid after a full parse', function()
+ exec_lua('vim.treesitter.get_parser():parse(true)')
+ eq(true, exec_lua('return vim.treesitter.get_parser():is_valid(true)'))
+ eq(true, exec_lua('return vim.treesitter.get_parser():is_valid()'))
+ end)
+
+ it('is fully valid after a parsing a range on parsed tree', function()
+ exec_lua('vim.treesitter.get_parser():parse({5, 7})')
+ eq(true, exec_lua('return vim.treesitter.get_parser():is_valid(true)'))
+ eq(true, exec_lua('return vim.treesitter.get_parser():is_valid()'))
+ end)
+
+ describe('when adding content with injections', function()
+ before_each(function()
+ feed('G')
+ insert(dedent[[
+ >lua
+ local a = {}
+ <
+
+ ]])
+ end)
+
+ it('is fully invalid after changes', function()
+ eq(false, exec_lua('return vim.treesitter.get_parser():is_valid(true)'))
+ eq(false, exec_lua('return vim.treesitter.get_parser():is_valid()'))
+ end)
+
+ it('is valid excluding, invalid including children after a rangeless parse', function()
+ exec_lua('vim.treesitter.get_parser():parse()')
+ eq(true, exec_lua('return vim.treesitter.get_parser():is_valid(true)'))
+ eq(false, exec_lua('return vim.treesitter.get_parser():is_valid()'))
+ end)
+
+ it('is fully valid after a range parse that leads to parsing not parsed injections', function()
+ exec_lua('vim.treesitter.get_parser():parse({5, 7})')
+ eq(true, exec_lua('return vim.treesitter.get_parser():is_valid(true)'))
+ eq(true, exec_lua('return vim.treesitter.get_parser():is_valid()'))
+ end)
+
+ it('is valid excluding, invalid including children after a range parse that does not lead to parsing not parsed injections', function()
+ exec_lua('vim.treesitter.get_parser():parse({2, 4})')
+ eq(true, exec_lua('return vim.treesitter.get_parser():is_valid(true)'))
+ eq(false, exec_lua('return vim.treesitter.get_parser():is_valid()'))
+ end)
+ end)
+
+ describe('when removing content with injections', function()
+ before_each(function()
+ feed('G')
+ insert(dedent[[
+ >lua
+ local a = {}
+ <
+
+ >lua
+ local a = {}
+ <
+
+ ]])
+
+ exec_lua('vim.treesitter.get_parser():parse(true)')
+
+ feed('Gd3k')
+ end)
+
+ it('is fully invalid after changes', function()
+ eq(false, exec_lua('return vim.treesitter.get_parser():is_valid(true)'))
+ eq(false, exec_lua('return vim.treesitter.get_parser():is_valid()'))
+ end)
+
+ it('is valid excluding, invalid including children after a rangeless parse', function()
+ exec_lua('vim.treesitter.get_parser():parse()')
+ eq(true, exec_lua('return vim.treesitter.get_parser():is_valid(true)'))
+ eq(false, exec_lua('return vim.treesitter.get_parser():is_valid()'))
+ end)
+
+ it('is fully valid after a range parse that leads to parsing modified child tree', function()
+ exec_lua('vim.treesitter.get_parser():parse({5, 7})')
+ eq(true, exec_lua('return vim.treesitter.get_parser():is_valid(true)'))
+ eq(true, exec_lua('return vim.treesitter.get_parser():is_valid()'))
+ end)
+
+ it('is valid excluding, invalid including children after a range parse that does not lead to parsing modified child tree', function()
+ exec_lua('vim.treesitter.get_parser():parse({2, 4})')
+ eq(true, exec_lua('return vim.treesitter.get_parser():is_valid(true)'))
+ eq(false, exec_lua('return vim.treesitter.get_parser():is_valid()'))
+ end)
+ end)
+ end)
end)