mirror of
https://github.com/neovim/neovim.git
synced 2025-10-26 12:27:24 +00:00
perf(treesitter): don't fetch parser for each fold line
**Problem:** The treesitter `foldexpr` calls `get_parser()` for each line in the buffer when calculating folds. This can be incredibly slow for buffers where a parser cannot be found (because the result is not cached), and exponentially more so when the user has many `runtimepath`s. **Solution:** Only fetch the parser when it is needed; that is, only when initializing fold data for a buffer. Co-authored-by: Jongwook Choi <wookayin@gmail.com> Co-authored-by: Justin M. Keyes <justinkz@gmail.com>
This commit is contained in:
committed by
Christian Clason
parent
b67fcd0488
commit
d9ee0d2984
@@ -19,14 +19,19 @@ local api = vim.api
|
||||
---The range on which to evaluate foldexpr.
|
||||
---When in insert mode, the evaluation is deferred to InsertLeave.
|
||||
---@field foldupdate_range? Range2
|
||||
---
|
||||
---The treesitter parser associated with this buffer.
|
||||
---@field parser? vim.treesitter.LanguageTree
|
||||
local FoldInfo = {}
|
||||
FoldInfo.__index = FoldInfo
|
||||
|
||||
---@private
|
||||
function FoldInfo.new()
|
||||
---@param bufnr integer
|
||||
function FoldInfo.new(bufnr)
|
||||
return setmetatable({
|
||||
levels0 = {},
|
||||
levels = {},
|
||||
parser = ts.get_parser(bufnr, nil, { error = false }),
|
||||
}, FoldInfo)
|
||||
end
|
||||
|
||||
@@ -69,7 +74,10 @@ local function compute_folds_levels(bufnr, info, srow, erow, parse_injections)
|
||||
srow = srow or 0
|
||||
erow = erow or api.nvim_buf_line_count(bufnr)
|
||||
|
||||
local parser = assert(ts.get_parser(bufnr, nil, { error = false }))
|
||||
local parser = info.parser
|
||||
if not parser then
|
||||
return
|
||||
end
|
||||
|
||||
parser:parse(parse_injections and { srow, erow } or nil)
|
||||
|
||||
@@ -347,13 +355,21 @@ function M.foldexpr(lnum)
|
||||
lnum = lnum or vim.v.lnum
|
||||
local bufnr = api.nvim_get_current_buf()
|
||||
|
||||
local parser = ts.get_parser(bufnr, nil, { error = false })
|
||||
if not parser then
|
||||
return '0'
|
||||
end
|
||||
|
||||
if not foldinfos[bufnr] then
|
||||
foldinfos[bufnr] = FoldInfo.new()
|
||||
foldinfos[bufnr] = FoldInfo.new(bufnr)
|
||||
api.nvim_create_autocmd('BufUnload', {
|
||||
buffer = bufnr,
|
||||
once = true,
|
||||
callback = function()
|
||||
foldinfos[bufnr] = nil
|
||||
end,
|
||||
})
|
||||
|
||||
local parser = foldinfos[bufnr].parser
|
||||
if not parser then
|
||||
return '0'
|
||||
end
|
||||
|
||||
compute_folds_levels(bufnr, foldinfos[bufnr])
|
||||
|
||||
parser:register_cbs({
|
||||
@@ -383,7 +399,7 @@ api.nvim_create_autocmd('OptionSet', {
|
||||
or foldinfos[buf] and { buf }
|
||||
or {}
|
||||
for _, bufnr in ipairs(bufs) do
|
||||
foldinfos[bufnr] = FoldInfo.new()
|
||||
foldinfos[bufnr] = FoldInfo.new(bufnr)
|
||||
api.nvim_buf_call(bufnr, function()
|
||||
compute_folds_levels(bufnr, foldinfos[bufnr])
|
||||
end)
|
||||
|
||||
Reference in New Issue
Block a user