mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 18:55:14 -07:00
refactor(treesitter): delegate region calculation to treesitter (#22576)
This commit is contained in:
parent
469e6bfc56
commit
090ade4af6
7
.github/workflows/test.yml
vendored
7
.github/workflows/test.yml
vendored
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user