refactor(treesitter): delegate region calculation to treesitter (#22576)

This commit is contained in:
Lewis Russell 2023-04-04 12:58:16 +01:00 committed by GitHub
parent 469e6bfc56
commit 090ade4af6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 61 additions and 57 deletions

View File

@ -376,13 +376,13 @@ jobs:
libluajit-5.1-dev \
libmsgpack-dev \
libtermkey-dev \
libtree-sitter-dev \
libunibilium-dev \
libuv1-dev \
lua-filesystem \
lua-lpeg \
lua-mpack \
luajit
# libtree-sitter-dev \
# libvterm-dev \
# lua-luv-dev
@ -397,7 +397,10 @@ jobs:
# dependencies don't have the required version available. We use the
# bundled versions for these with the hopes of being able to remove them
# later on.
cmake -S cmake.deps -B .deps -G Ninja -D USE_BUNDLED=OFF -D USE_BUNDLED_LUV=ON -D USE_BUNDLED_LIBVTERM=ON
cmake -S cmake.deps -B .deps -G Ninja -D USE_BUNDLED=OFF \
-D USE_BUNDLED_LUV=ON \
-D USE_BUNDLED_LIBVTERM=ON \
-D USE_BUNDLED_TS=ON
cmake --build .deps
- name: Build

View File

@ -57,7 +57,9 @@ local Range = require('vim.treesitter._range')
---@field private _injection_query Query Queries defining injected languages
---@field private _opts table Options
---@field private _parser TSParser Parser for language
---@field private _regions Range6[][] List of regions this tree should manage and parse
---@field private _regions Range6[][]?
---List of regions this tree should manage and parse. If nil then regions are
---taken from _trees. This is mostly a short-lived cache for included_regions()
---@field private _lang string Language name
---@field private _source (integer|string) Buffer or string to parse
---@field private _trees TSTree[] Reference to parsed tree (one for each language)
@ -91,7 +93,6 @@ function LanguageTree.new(source, lang, opts)
_source = source,
_lang = lang,
_children = {},
_regions = {},
_trees = {},
_opts = opts,
_injection_query = injections[lang] and query.parse(lang, injections[lang])
@ -237,27 +238,21 @@ function LanguageTree:parse()
--- At least 1 region is invalid
if not self:is_valid(true) then
local function _parsetree(index)
local parse_time, tree, tree_changes =
tcall(self._parser.parse, self._parser, self._trees[index], self._source)
-- If there are no ranges, set to an empty list
-- so the included ranges in the parser are cleared.
for i, ranges in ipairs(self:included_regions()) do
if not self._valid or not self._valid[i] then
self._parser:set_included_ranges(ranges)
local parse_time, tree, tree_changes =
tcall(self._parser.parse, self._parser, self._trees[i], self._source)
self:_do_callback('changedtree', tree_changes, tree)
self._trees[index] = tree
vim.list_extend(changes, tree_changes)
self:_do_callback('changedtree', tree_changes, tree)
self._trees[i] = tree
vim.list_extend(changes, tree_changes)
total_parse_time = total_parse_time + parse_time
regions_parsed = regions_parsed + 1
end
if #self._regions > 0 then
for i, ranges in ipairs(self._regions) do
if not self._valid or not self._valid[i] then
self._parser:set_included_ranges(ranges)
_parsetree(i)
end
total_parse_time = total_parse_time + parse_time
regions_parsed = regions_parsed + 1
end
else
_parsetree(1)
end
end
@ -403,7 +398,7 @@ function LanguageTree:_iter_regions(fn)
local all_valid = true
for i, region in ipairs(self._regions) do
for i, region in ipairs(self:included_regions()) do
if self._valid[i] == nil then
self._valid[i] = true
end
@ -454,7 +449,7 @@ function LanguageTree:set_included_regions(new_regions)
end
end
if #self._regions ~= #new_regions then
if #self:included_regions() ~= #new_regions then
self._trees = {}
self:invalidate()
else
@ -462,13 +457,28 @@ function LanguageTree:set_included_regions(new_regions)
return vim.deep_equal(new_regions[i], region)
end)
end
self._regions = new_regions
end
---Gets the set of included regions
---@return integer[][]
function LanguageTree:included_regions()
return self._regions
if self._regions then
return self._regions
end
if #self._trees == 0 then
return { {} }
end
local regions = {} ---@type Range6[][]
for i, _ in ipairs(self._trees) do
regions[i] = self._trees[i]:included_ranges(true)
end
self._regions = regions
return regions
end
---@private
@ -721,6 +731,8 @@ function LanguageTree:_edit(
)
end
self._regions = nil
local changed_range = {
start_row,
start_col,
@ -730,42 +742,12 @@ function LanguageTree:_edit(
end_byte_old,
}
local new_range = {
start_row,
start_col,
start_byte,
end_row_new,
end_col_new,
end_byte_new,
}
if #self._regions == 0 then
self._valid = false
end
-- Validate regions after editing the tree
self:_iter_regions(function(_, region)
for i, r in ipairs(region) do
for _, r in ipairs(region) do
if Range.intercepts(r, changed_range) then
return false
end
-- Range after change. Adjust
if Range.cmp_pos.gt(r[1], r[2], changed_range[4], changed_range[5]) then
local byte_offset = new_range[6] - changed_range[6]
local row_offset = new_range[4] - changed_range[4]
-- Update the range to avoid invalidation in set_included_regions()
-- which will compare the regions against the parsed injection regions
region[i] = {
r[1] + row_offset,
r[2],
r[3] + byte_offset,
r[4] + row_offset,
r[5],
r[6] + byte_offset,
}
end
end
return true
end)

View File

@ -21,7 +21,7 @@ find_package(Iconv REQUIRED)
find_package(Libtermkey 0.22 REQUIRED)
find_package(Libvterm 0.3 REQUIRED)
find_package(Msgpack 1.0.0 REQUIRED)
find_package(Treesitter REQUIRED)
find_package(Treesitter 0.20.8 REQUIRED)
find_package(Unibilium 2.0 REQUIRED)
target_link_libraries(main_lib INTERFACE

View File

@ -64,6 +64,7 @@ static struct luaL_Reg tree_meta[] = {
{ "__tostring", tree_tostring },
{ "root", tree_root },
{ "edit", tree_edit },
{ "included_ranges", tree_get_ranges },
{ "copy", tree_copy },
{ NULL, NULL }
};
@ -512,6 +513,24 @@ static int tree_edit(lua_State *L)
return 0;
}
static int tree_get_ranges(lua_State *L)
{
TSTree **tree = tree_check(L, 1);
if (!(*tree)) {
return 0;
}
bool include_bytes = (lua_gettop(L) >= 2) && lua_toboolean(L, 2);
uint32_t len;
TSRange *ranges = ts_tree_included_ranges(*tree, &len);
push_ranges(L, ranges, len, include_bytes);
xfree(ranges);
return 1;
}
// Use the top of the stack (without popping it) to create a TSRange, it can be
// either a lua table or a TSNode
static void range_from_lua(lua_State *L, TSRange *range)