aboutsummaryrefslogtreecommitdiff
path: root/runtime/lua/vim/treesitter
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/lua/vim/treesitter')
-rw-r--r--runtime/lua/vim/treesitter/_headings.lua8
-rw-r--r--runtime/lua/vim/treesitter/_meta/misc.lua4
-rw-r--r--runtime/lua/vim/treesitter/languagetree.lua123
3 files changed, 58 insertions, 77 deletions
diff --git a/runtime/lua/vim/treesitter/_headings.lua b/runtime/lua/vim/treesitter/_headings.lua
index 885d014a89..bfa468ad88 100644
--- a/runtime/lua/vim/treesitter/_headings.lua
+++ b/runtime/lua/vim/treesitter/_headings.lua
@@ -40,10 +40,6 @@ local heading_queries = {
]],
}
-local function hash_tick(bufnr)
- return tostring(vim.b[bufnr].changedtick)
-end
-
---@class TS.Heading
---@field bufnr integer
---@field lnum integer
@@ -53,7 +49,7 @@ end
--- Extract headings from buffer
--- @param bufnr integer buffer to extract headings from
--- @return TS.Heading[]
-local get_headings = vim.func._memoize(hash_tick, function(bufnr)
+local get_headings = function(bufnr)
local lang = ts.language.get_lang(vim.bo[bufnr].filetype)
if not lang then
return {}
@@ -85,7 +81,7 @@ local get_headings = vim.func._memoize(hash_tick, function(bufnr)
end
end
return headings
-end)
+end
--- Shows an Outline (table of contents) of the current buffer, in the loclist.
function M.show_toc()
diff --git a/runtime/lua/vim/treesitter/_meta/misc.lua b/runtime/lua/vim/treesitter/_meta/misc.lua
index 07a1c921c7..9b9cc4eb54 100644
--- a/runtime/lua/vim/treesitter/_meta/misc.lua
+++ b/runtime/lua/vim/treesitter/_meta/misc.lua
@@ -5,12 +5,10 @@ error('Cannot require a meta file')
---@alias TSLoggerCallback fun(logtype: 'parse'|'lex', msg: string)
---@class TSParser: userdata
----@field parse fun(self: TSParser, tree: TSTree?, source: integer|string, include_bytes: boolean): TSTree, (Range4|Range6)[]
+---@field parse fun(self: TSParser, tree: TSTree?, source: integer|string, include_bytes: boolean, timeout_ns: integer?): TSTree?, (Range4|Range6)[]
---@field reset fun(self: TSParser)
---@field included_ranges fun(self: TSParser, include_bytes: boolean?): integer[]
---@field set_included_ranges fun(self: TSParser, ranges: (Range6|TSNode)[])
----@field set_timeout fun(self: TSParser, timeout: integer)
----@field timeout fun(self: TSParser): integer
---@field _set_logger fun(self: TSParser, lex: boolean, parse: boolean, cb: TSLoggerCallback)
---@field _logger fun(self: TSParser): TSLoggerCallback
diff --git a/runtime/lua/vim/treesitter/languagetree.lua b/runtime/lua/vim/treesitter/languagetree.lua
index f2e745ec65..6f0e377d2f 100644
--- a/runtime/lua/vim/treesitter/languagetree.lua
+++ b/runtime/lua/vim/treesitter/languagetree.lua
@@ -43,8 +43,10 @@
local query = require('vim.treesitter.query')
local language = require('vim.treesitter.language')
local Range = require('vim.treesitter._range')
+local hrtime = vim.uv.hrtime
-local default_parse_timeout_ms = 3
+-- Parse in 3ms chunks.
+local default_parse_timeout_ns = 3 * 1000000
---@type Range2
local entire_document_range = { 0, math.huge }
@@ -198,16 +200,16 @@ function LanguageTree:_set_logger()
self._parser:_set_logger(log_lex, log_parse, self._logger)
end
----Measure execution time of a function
+---Measure execution time of a function, in nanoseconds.
---@generic R1, R2, R3
---@param f fun(): R1, R2, R3
---@return number, R1, R2, R3
local function tcall(f, ...)
- local start = vim.uv.hrtime()
+ local start = hrtime()
---@diagnostic disable-next-line
local r = { f(...) }
--- @type number
- local duration = (vim.uv.hrtime() - start) / 1000000
+ local duration = hrtime() - start
--- @diagnostic disable-next-line: redundant-return-value
return duration, unpack(r)
end
@@ -388,18 +390,29 @@ function LanguageTree:_parse_regions(range, thread_state)
)
then
self._parser:set_included_ranges(ranges)
- self._parser:set_timeout(thread_state.timeout and thread_state.timeout * 1000 or 0) -- ms -> micros
- local parse_time, tree, tree_changes =
- tcall(self._parser.parse, self._parser, self._trees[i], self._source, true)
+ local parse_time, tree, tree_changes = tcall(
+ self._parser.parse,
+ self._parser,
+ self._trees[i],
+ self._source,
+ true,
+ thread_state.timeout
+ )
while true do
if tree then
break
end
coroutine.yield(self._trees, false)
- parse_time, tree, tree_changes =
- tcall(self._parser.parse, self._parser, self._trees[i], self._source, true)
+ parse_time, tree, tree_changes = tcall(
+ self._parser.parse,
+ self._parser,
+ self._trees[i],
+ self._source,
+ true,
+ thread_state.timeout
+ )
end
self:_subtract_time(thread_state, parse_time)
@@ -503,7 +516,7 @@ function LanguageTree:_async_parse(range, on_parse)
local buf = is_buffer_parser and vim.b[source] or nil
local ct = is_buffer_parser and buf.changedtick or nil
local total_parse_time = 0
- local redrawtime = vim.o.redrawtime
+ local redrawtime = vim.o.redrawtime * 1000000
local thread_state = {} ---@type ParserThreadState
@@ -526,7 +539,7 @@ function LanguageTree:_async_parse(range, on_parse)
end
end
- thread_state.timeout = not vim.g._ts_force_sync_parsing and default_parse_timeout_ms or nil
+ thread_state.timeout = not vim.g._ts_force_sync_parsing and default_parse_timeout_ns or nil
local parse_time, trees, finished = tcall(parse, self, range, thread_state)
total_parse_time = total_parse_time + parse_time
@@ -868,35 +881,42 @@ end
---@alias vim.treesitter.languagetree.Injection table<string,table<integer,vim.treesitter.languagetree.InjectionElem>>
----@param t table<integer,vim.treesitter.languagetree.Injection>
----@param tree_index integer
+---@param t vim.treesitter.languagetree.Injection
---@param pattern integer
---@param lang string
---@param combined boolean
---@param ranges Range6[]
-local function add_injection(t, tree_index, pattern, lang, combined, ranges)
+---@param result table<string,Range6[][]>
+local function add_injection(t, pattern, lang, combined, ranges, result)
if #ranges == 0 then
-- Make sure not to add an empty range set as this is interpreted to mean the whole buffer.
return
end
- -- Each tree index should be isolated from the other nodes.
- if not t[tree_index] then
- t[tree_index] = {}
+ if not result[lang] then
+ result[lang] = {}
end
- if not t[tree_index][lang] then
- t[tree_index][lang] = {}
+ if not combined then
+ table.insert(result[lang], ranges)
+ return
end
- -- Key this by pattern. If combined is set to true all captures of this pattern
+ if not t[lang] then
+ t[lang] = {}
+ end
+
+ -- Key this by pattern. For combined injections, all captures of this pattern
-- will be parsed by treesitter as the same "source".
- -- If combined is false, each "region" will be parsed as a single source.
- if not t[tree_index][lang][pattern] then
- t[tree_index][lang][pattern] = { combined = combined, regions = {} }
+ if not t[lang][pattern] then
+ local regions = {}
+ t[lang][pattern] = regions
+ table.insert(result[lang], regions)
end
- table.insert(t[tree_index][lang][pattern].regions, ranges)
+ for _, range in ipairs(ranges) do
+ table.insert(t[lang][pattern], range)
+ end
end
-- TODO(clason): replace by refactored `ts.has_parser` API (without side effects)
@@ -964,19 +984,6 @@ function LanguageTree:_get_injection(match, metadata)
return lang, combined, ranges
end
---- Can't use vim.tbl_flatten since a range is just a table.
----@param regions Range6[][]
----@return Range6[]
-local function combine_regions(regions)
- local result = {} ---@type Range6[]
- for _, region in ipairs(regions) do
- for _, range in ipairs(region) do
- result[#result + 1] = range
- end
- end
- return result
-end
-
--- Gets language injection regions by language.
---
--- This is where most of the injection processing occurs.
@@ -993,13 +1000,16 @@ function LanguageTree:_get_injections(range, thread_state)
return {}
end
- ---@type table<integer,vim.treesitter.languagetree.Injection>
- local injections = {}
- local start = vim.uv.hrtime()
+ local start = hrtime()
+
+ ---@type table<string,Range6[][]>
+ local result = {}
local full_scan = range == true or self._injection_query.has_combined_injections
- for index, tree in pairs(self._trees) do
+ for _, tree in pairs(self._trees) do
+ ---@type vim.treesitter.languagetree.Injection
+ local injections = {}
local root_node = tree:root()
local start_line, end_line ---@type integer, integer
if full_scan then
@@ -1013,38 +1023,15 @@ function LanguageTree:_get_injections(range, thread_state)
do
local lang, combined, ranges = self:_get_injection(match, metadata)
if lang then
- add_injection(injections, index, pattern, lang, combined, ranges)
+ add_injection(injections, pattern, lang, combined, ranges, result)
else
self:_log('match from injection query failed for pattern', pattern)
end
-- Check the current function duration against the timeout, if it exists.
- local current_time = vim.uv.hrtime()
- self:_subtract_time(thread_state, (current_time - start) / 1000000)
- start = current_time
- end
- end
-
- ---@type table<string,Range6[][]>
- local result = {}
-
- -- Generate a map by lang of node lists.
- -- Each list is a set of ranges that should be parsed together.
- for _, lang_map in pairs(injections) do
- for lang, patterns in pairs(lang_map) do
- if not result[lang] then
- result[lang] = {}
- end
-
- for _, entry in pairs(patterns) do
- if entry.combined then
- table.insert(result[lang], combine_regions(entry.regions))
- else
- for _, ranges in pairs(entry.regions) do
- table.insert(result[lang], ranges)
- end
- end
- end
+ local current_time = hrtime()
+ self:_subtract_time(thread_state, current_time - start)
+ start = hrtime()
end
end