diff options
author | L Lllvvuu <git@llllvvuu.dev> | 2023-09-19 21:41:07 -0700 |
---|---|---|
committer | Lewis Russell <me@lewisr.dev> | 2023-09-22 12:51:51 +0100 |
commit | e353c869cea4541d00d627ec82724d3f247225a3 (patch) | |
tree | 09f7fb19e9ad60f5dffbdd5fa33b3e9672890b48 | |
parent | b7763d7f6b7fdcabe06658c664457df8bc147563 (diff) | |
download | rneovim-e353c869cea4541d00d627ec82724d3f247225a3.tar.gz rneovim-e353c869cea4541d00d627ec82724d3f247225a3.tar.bz2 rneovim-e353c869cea4541d00d627ec82724d3f247225a3.zip |
fix(languagetree): don't treat unparsed nodes as occupying full range
This is incorrect in the following scenario:
1. The language tree is Lua > Vim > Lua.
2. An edit simultaneously wipes out the `_regions` of all nodes, while
taking the Vim injection off-screen.
3. The Vim injection is not re-parsed, so the child Lua `_regions` is
still `nil`.
4. The child Lua is assumed, incorrectly, to occupy the whole document.
5. This causes the injections to be parsed again, resulting in Lua > Vim
> Lua > Vim.
6. Now, by the same process, Vim ends up with its range assumed over the
whole document. Now the parse is broken and results in broken
highlighting and poor performance.
It should be fine to instead treat an unparsed node as occupying
nothing (i.e. effectively non-existent). Since, either:
- The parent was just parsed, hence defining `_regions`
- The parent was not just parsed, in which case this node doesn't need
to be parsed either.
Also, the name `has_regions` is confusing; it seems to simply
mean the opposite of "root" or "full_document". However, this PR does
not touch it.
-rw-r--r-- | runtime/lua/vim/treesitter/languagetree.lua | 4 | ||||
-rw-r--r-- | test/functional/treesitter/highlight_spec.lua | 64 |
2 files changed, 66 insertions, 2 deletions
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua index b2c4e9167d..670f2797b7 100644 --- a/runtime/lua/vim/treesitter/languagetree.lua +++ b/runtime/lua/vim/treesitter/languagetree.lua @@ -650,8 +650,8 @@ function LanguageTree:included_regions() return self._regions end - if not self._has_regions or next(self._trees) == nil then - -- treesitter.c will default empty ranges to { -1, -1, -1, -1, -1, -1} + if not self._has_regions then + -- treesitter.c will default empty ranges to { -1, -1, -1, -1, -1, -1} (the full range) return { {} } end diff --git a/test/functional/treesitter/highlight_spec.lua b/test/functional/treesitter/highlight_spec.lua index 0aa0cdd6d6..e037c9e215 100644 --- a/test/functional/treesitter/highlight_spec.lua +++ b/test/functional/treesitter/highlight_spec.lua @@ -838,3 +838,67 @@ describe('treesitter highlighting (help)', function() end) end) + +describe('treesitter highlighting (nested injections)', function() + local screen + + before_each(function() + screen = Screen.new(80, 7) + screen:attach() + screen:set_default_attr_ids { + [1] = {foreground = Screen.colors.SlateBlue}; + [2] = {bold = true, foreground = Screen.colors.Brown}; + [3] = {foreground = Screen.colors.Cyan4}; + [4] = {foreground = Screen.colors.Fuchsia}; + } + end) + + it("correctly redraws nested injections (GitHub #25252)", function() + insert[=[ +function foo() print("Lua!") end + +local lorem = { + ipsum = {}, + bar = {}, +} +vim.cmd([[ + augroup RustLSP + autocmd CursorHold silent! lua vim.lsp.buf.document_highlight() + augroup END +]]) + ]=] + + exec_lua [[ + vim.opt.scrolloff = 0 + vim.bo.filetype = 'lua' + vim.treesitter.start() + ]] + + -- invalidate the language tree + feed("ggi--[[<ESC>04x") + + screen:expect{grid=[[ + {2:^function} {3:foo}{1:()} {1:print(}{4:"Lua!"}{1:)} {2:end} | + | + {2:local} {3:lorem} {2:=} {1:{} | + {3:ipsum} {2:=} {1:{},} | + {3:bar} {2:=} {1:{},} | + {1:}} | + | + ]]} + + -- spam newline insert/delete to invalidate Lua > Vim > Lua region + feed("3jo<ESC>ddko<ESC>ddko<ESC>ddko<ESC>ddk0") + + screen:expect{grid=[[ + {2:function} {3:foo}{1:()} {1:print(}{4:"Lua!"}{1:)} {2:end} | + | + {2:local} {3:lorem} {2:=} {1:{} | + ^ {3:ipsum} {2:=} {1:{},} | + {3:bar} {2:=} {1:{},} | + {1:}} | + | + ]]} + end) + +end) |