fix(treesitter): make foldexpr work without highlighting (#24167)

Problem: Treesitter fold is not updated if treesitter hightlight is not
active. More precisely, updating folds requires `LanguageTree:parse()`.

Solution: Call `parse()` before computing folds and compute folds when
lines are added/removed.

This doesn't guarantee correctness of the folds, because some changes
that don't add/remove line won't update the folds even if they should
(e.g. adding pair of braces). But it is good enough for most cases,
while not introducing big overhead.

Also, if highlighting is active, it is likely that
`TSHighlighter._on_buf` already ran `parse()` (or vice versa).
This commit is contained in:
Jaehwang Jung 2023-06-28 03:05:09 +09:00 committed by GitHub
parent ab65a98adb
commit c7e7f1d4b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 30 additions and 13 deletions

View File

@ -162,9 +162,7 @@ local function get_folds_levels(bufnr, info, srow, erow)
local parser = ts.get_parser(bufnr)
if not parser:is_valid() then
return
end
parser:parse()
parser:for_each_tree(function(tree, ltree)
local query = ts.query.get(ltree:lang(), 'folds')
@ -283,10 +281,12 @@ local function on_bytes(bufnr, foldinfo, start_row, old_row, new_row)
local end_row_old = start_row + old_row
local end_row_new = start_row + new_row
if new_row < old_row then
foldinfo:remove_range(end_row_new, end_row_old)
elseif new_row > old_row then
foldinfo:add_range(start_row, end_row_new)
if new_row ~= old_row then
if new_row < old_row then
foldinfo:remove_range(end_row_new, end_row_old)
else
foldinfo:add_range(start_row, end_row_new)
end
schedule_if_loaded(bufnr, function()
get_folds_levels(bufnr, foldinfo, start_row, end_row_new)
recompute_folds()

View File

@ -922,12 +922,6 @@ int x = INT_MAX;
[19] = '1' }, get_fold_levels())
helpers.command('1,2d')
helpers.poke_eventloop()
exec_lua([[vim.treesitter.get_parser():parse()]])
helpers.poke_eventloop()
helpers.sleep(100)
eq({
[1] = '0',
@ -947,6 +941,29 @@ int x = INT_MAX;
[15] = '2',
[16] = '1',
[17] = '0' }, get_fold_levels())
helpers.command('1put!')
eq({
[1] = '>1',
[2] = '1',
[3] = '1',
[4] = '1',
[5] = '>2',
[6] = '2',
[7] = '2',
[8] = '1',
[9] = '1',
[10] = '>2',
[11] = '2',
[12] = '2',
[13] = '2',
[14] = '2',
[15] = '>3',
[16] = '3',
[17] = '3',
[18] = '2',
[19] = '1' }, get_fold_levels())
end)
it('tracks the root range properly (#22911)', function()