Skip to content

Commit f4e8e1a

Browse files
committed
perf: add cache for indent
1 parent 48bbc13 commit f4e8e1a

File tree

3 files changed

+61
-40
lines changed

3 files changed

+61
-40
lines changed

lua/hlchunk/mods/indent/init.lua

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ local fn = vim.fn
1111
local ROWS_INDENT_RETCODE = indentHelper.ROWS_INDENT_RETCODE
1212

1313
---@class IndentMetaInfo : MetaInfo
14+
---@field cache table<number, number>
1415

1516
local constructor = function(self, conf, meta)
1617
local default_meta = {
@@ -20,6 +21,7 @@ local constructor = function(self, conf, meta)
2021
ns_id = api.nvim_create_namespace("indent"),
2122
shiftwidth = fn.shiftwidth(),
2223
leftcol = fn.winsaveview().leftcol,
24+
cache = {},
2325
}
2426

2527
BaseMod.init(self, conf, meta)
@@ -35,7 +37,7 @@ end
3537
---@overload fun(conf?: UserIndentConf, meta?: MetaInfo): IndentMod
3638
local IndentMod = class(BaseMod, constructor)
3739

38-
function IndentMod:renderLine(bufnr, index, blankLen)
40+
function IndentMod:renderLine(bufnr, lnum, blankLen)
3941
local row_opts = {
4042
virt_text_pos = "overlay",
4143
hl_mode = "combine",
@@ -58,14 +60,30 @@ function IndentMod:renderLine(bufnr, index, blankLen)
5860
-- return
5961
-- end
6062
-- end
61-
api.nvim_buf_set_extmark(bufnr, self.meta.ns_id, index - 1, 0, row_opts)
63+
api.nvim_buf_set_extmark(bufnr, self.meta.ns_id, lnum, 0, row_opts)
6264
end
6365
end
6466

6567
function IndentMod:render(range)
6668
self:clear(range)
6769

68-
local retcode, rows_indent = indentHelper.get_rows_indent(range, {
70+
-- narrow the range that should get indent
71+
local non_cached_start = range.start
72+
local non_cached_finish = range.finish
73+
for i = range.start, range.finish do
74+
if not self.meta.cache[i] then
75+
non_cached_start = i
76+
break
77+
end
78+
end
79+
for i = non_cached_start, range.finish do
80+
if self.meta.cache[i] then
81+
non_cached_finish = i - 1
82+
break
83+
end
84+
end
85+
86+
local retcode, rows_indent = indentHelper.get_rows_indent(Scope(range.bufnr, non_cached_start, non_cached_finish), {
6987
use_treesitter = self.conf.use_treesitter,
7088
virt_indent = true,
7189
})
@@ -75,9 +93,11 @@ function IndentMod:render(range)
7593
end
7694
return
7795
end
78-
79-
for index, _ in pairs(rows_indent) do
80-
self:renderLine(range.bufnr, index, rows_indent[index])
96+
for lnum, indent in pairs(rows_indent) do
97+
self.meta.cache[lnum] = indent
98+
end
99+
for lnum = range.start, range.finish do
100+
self:renderLine(range.bufnr, lnum, self.meta.cache[lnum])
81101
end
82102
end
83103

@@ -116,7 +136,10 @@ function IndentMod:createAutocmd()
116136
})
117137
api.nvim_create_autocmd({ "TextChanged", "TextChangedI" }, {
118138
group = self.meta.augroup_name,
119-
callback = throttle_render_cb_with_pre_hook,
139+
callback = function(e)
140+
self.meta.cache = {}
141+
throttle_render_cb_with_pre_hook(e)
142+
end,
120143
})
121144
api.nvim_create_autocmd({ "BufWinEnter" }, {
122145
group = self.meta.augroup_name,

lua/hlchunk/utils/cFunc.lua

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
11
local ffi = require("ffi")
22

33
ffi.cdef([[
4-
typedef struct {} Error;
5-
typedef struct file_buffer buf_T;
6-
typedef int32_t linenr_T;
7-
buf_T *find_buffer_by_handle(int buffer, Error *err);
8-
int get_indent_buf(buf_T *buf, linenr_T lnum);
9-
int get_sw_value(buf_T *buf);
4+
typedef struct {} Error;
5+
typedef struct file_buffer buf_T;
6+
typedef int32_t linenr_T;
7+
buf_T *find_buffer_by_handle(int buffer, Error *err);
8+
int get_indent_buf(buf_T *buf, linenr_T lnum);
9+
int get_sw_value(buf_T *buf);
1010
]])
1111
local C = ffi.C
1212

1313
local M = {}
1414

1515
---@param bufnr number
1616
---@param row number 0-index
17+
---@return number
1718
function M.get_indent(bufnr, row)
19+
local line_cnt = vim.api.nvim_buf_line_count(bufnr)
20+
if row >= line_cnt then
21+
return -1
22+
end
1823
local handler = C.find_buffer_by_handle(bufnr, ffi.new("Error"))
1924
return C.get_indent_buf(handler, row + 1)
2025
end

lua/hlchunk/utils/indentHelper.lua

Lines changed: 20 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,13 @@ local fn = vim.fn
22
local cFunc = require("hlchunk.utils.cFunc")
33

44
-- get the virtual indent of the given line
5-
---@param rows_indent table<number, number>
5+
---@param bufnr number
66
---@param line number
77
---@return number
8-
local function get_virt_indent(rows_indent, line)
9-
local cur = line + 1
10-
while rows_indent[cur] do
11-
if rows_indent[cur] == 0 then
12-
break
13-
elseif rows_indent[cur] > 0 then
14-
return rows_indent[cur]
15-
end
16-
cur = cur + 1
17-
end
18-
return -1
8+
local function get_virt_indent(bufnr, line)
9+
return vim.api.nvim_buf_call(bufnr, function()
10+
return cFunc.get_indent(bufnr, fn.nextnonblank(line + 1) - 1)
11+
end)
1912
end
2013

2114
local indentHelper = {}
@@ -42,39 +35,39 @@ indentHelper.ROWS_INDENT_RETCODE = {
4235
NO_TS = 1,
4336
}
4437

38+
---@param range Scope
39+
---@return ROWS_INDENT_RETCODE
40+
---@return table<number, number>
4541
local function get_rows_indent_by_context(range)
46-
local begRow = range.start + 1
47-
local endRow = range.finish + 1
48-
4942
local rows_indent = {}
5043

51-
for i = endRow, begRow, -1 do
52-
rows_indent[i] = cFunc.get_indent(range.bufnr, i - 1)
53-
if rows_indent[i] == 0 and #fn.getline(i) == 0 then
54-
rows_indent[i] = get_virt_indent(rows_indent, i) or -1
44+
for i = range.finish, range.start, -1 do
45+
rows_indent[i] = cFunc.get_indent(range.bufnr, i)
46+
if rows_indent[i] == 0 and #fn.getline(i + 1) == 0 then
47+
rows_indent[i] = get_virt_indent(range.bufnr, i)
5548
end
5649
end
5750

5851
return indentHelper.ROWS_INDENT_RETCODE.OK, rows_indent
5952
end
6053

54+
---@param range Scope
55+
---@return ROWS_INDENT_RETCODE
56+
---@return table<number, number>
6157
local function get_rows_indent_by_treesitter(range)
62-
local begRow = range.start + 1
63-
local endRow = range.finish + 1
64-
6558
local rows_indent = {}
6659
local ts_indent_status, ts_indent = pcall(require, "nvim-treesitter.indent")
6760
if not ts_indent_status then
6861
return indentHelper.ROWS_INDENT_RETCODE.NO_TS, {}
6962
end
7063

71-
for i = endRow, begRow, -1 do
64+
for i = range.start, range.finish, -1 do
7265
rows_indent[i] = vim.api.nvim_buf_call(range.bufnr, function()
73-
local indent = ts_indent.get_indent(i)
66+
local indent = ts_indent.get_indent(i + 1)
7467
if indent == -1 then
75-
indent = fn.indent(i)
76-
if indent == 0 and #fn.getline(i) == 0 then
77-
indent = get_virt_indent(rows_indent, i) or -1
68+
indent = fn.indent(i + 1)
69+
if indent == 0 and #fn.getline(i + 1) == 0 then
70+
indent = get_virt_indent(range.bufnr, i)
7871
end
7972
end
8073
---@diagnostic disable-next-line: redundant-return-value

0 commit comments

Comments
 (0)