Skip to content

Commit 09476e2

Browse files
committed
Merge branch 'dev'
2 parents 0eb86c7 + 3a9ce3a commit 09476e2

File tree

9 files changed

+127
-34
lines changed

9 files changed

+127
-34
lines changed

docs/en/indent.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,24 @@ When rendering, the first level will use the first character, the second level w
4040

4141
- `delay` is a number that presents a millisecond value, because rendering is very time-consuming in some cases, a throttle function is used to limit the rendering frequency, the larger the value, the smoother the screen scrolling, but at the same time, a larger part of the content will not be rendered (until after delay milliseconds), which defaults to 100
4242

43+
- `filter_list` is a `Lua` list where you can define some `filter` functions to filter the rendered characters. The functions defined here must accept one parameter, `render_char_info`, which contains the following fields:
44+
- `level`: indicates the current indentation level
45+
- `lnum`: indicates the line number where the current indented character is located (starting from 0)
46+
- `virt_text_win_col`: represents the column on the screen where the current indented character is located (starting from 0). For more information, refer to [nvim_buf_set_extmark function](https://neovim.io/doc/user/api.html#nvim_buf_set_extmark())
47+
- `virt_text`: same as above, this is a parameter of the `nvim_buf_set_extmark` function; generally, you do not need to set this field.
48+
49+
let's look an example here, if you don't want to show the first level of indent line, you can set like this:
50+
51+
```lua
52+
filter_list = {
53+
function(v)
54+
return v.level ~= 1
55+
end,
56+
},
57+
```
58+
59+
60+
4361
Like chunk, we also need to pay extra attention to the common configuration style:
4462

4563
- Here, style is a RGB string or a table. If it is a string, all indent lines will be rendered in this color. If it is a table, it can be written in two ways:

docs/zh_CN/indent.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,23 @@ local default_conf = {
4040

4141
- `delay` 是一个用来表示毫秒值的数字,这是由于某些情况下渲染非常耗时,采用节流函数对渲染频率进行了限制,数值越大,滚动屏幕时越流畅,但同时也会看到较大部分的内容未被渲染(直到 delay 毫秒后),默认为 100
4242

43+
- `filter_list` 是一个 `Lua` 列表,其中可以定义一些 `filter` 函数,用来对渲染的字符进行过滤。你在这里定义的函数必须接受一个参数 `render_char_info`,这个参数包含如下字段
44+
- `level` 表示当前缩进层级
45+
- `lnum` 表示当前缩进字符所在行(0 为起始行)
46+
- `virt_text_win_col` 当前缩进字符在屏幕上的所在列(0 为起始列)具体信息可以看 [nvim_buf_set_extmark 函数](https://neovim.io/doc/user/api.html#nvim_buf_set_extmark())的介绍信息
47+
- `virt_text` 同上,这是 `nvim_buf_set_extmark` 函数的一个参数,一般来说你不需要设置这个字段。
48+
49+
比如,如果你不希望渲染第一个 `level` 的字符,你可以按照如下方法设置
50+
51+
```lua
52+
filter_list = {
53+
function(v)
54+
return v.level ~= 1
55+
end,
56+
},
57+
```
58+
59+
4360
和 chunk 一样,我们需要额外注意 style 这个通用配置:
4461

4562
- 这里的 `style` 是一个 RGB 字符串或者一个表。如果是字符串,那么所有的缩进线将会采用这一种颜色来渲染,如果是表,可以有这两种写法:

lua/hlchunk/mods/chunk/init.lua

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ local ChunkConf = require("hlchunk.mods.chunk.chunk_conf")
33
local chunkHelper = require("hlchunk.utils.chunkHelper")
44
local LoopTask = require("hlchunk.utils.loopTask")
55
local debounce = require("hlchunk.utils.timer").debounce
6+
local debounce_throttle = require("hlchunk.utils.timer").debounce_throttle
67
local Pos = require("hlchunk.utils.position")
78
local Scope = require("hlchunk.utils.scope")
89
local cFunc = require("hlchunk.utils.cFunc")
@@ -156,7 +157,7 @@ function ChunkMod:render(range, opts)
156157
row_opts.virt_text = { { vt, text_hl } }
157158
row_opts.virt_text_win_col = virt_text_win_col_list[i]
158159
local row = row_list[i]
159-
if api.nvim_buf_is_valid(range.bufnr) and api.nvim_buf_line_count(range.bufnr) > row then
160+
if row and api.nvim_buf_is_valid(range.bufnr) and api.nvim_buf_line_count(range.bufnr) > row then
160161
api.nvim_buf_set_extmark(range.bufnr, self.meta.ns_id, row, 0, row_opts)
161162
end
162163
end
@@ -202,11 +203,11 @@ function ChunkMod:createAutocmd()
202203
end
203204
end
204205
local db_render_cb = debounce(render_cb, self.conf.delay, false)
205-
local db_render_cb_imm = debounce(render_cb, self.conf.delay, true)
206+
local db_render_cb_imm = debounce_throttle(render_cb, self.conf.delay)
206207
local db_render_cb_with_pre_hook = function(event, opts)
207208
opts = opts or { lazy = false }
208209
local bufnr = event.buf
209-
if not (api.nvim_buf_is_valid(bufnr) and self:shouldRender(bufnr)) then
210+
if not self:shouldRender(bufnr) then
210211
return
211212
end
212213
if opts.lazy then

lua/hlchunk/mods/indent/indent_conf.lua

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ local BaseConf = require("hlchunk.mods.base_mod.base_conf")
1212
---@field chars table<string, string>
1313
---@field ahead_lines number
1414
---@field delay number default 50ms
15+
---@field filter_list table<number, function>
1516
---@overload fun(conf?: UserIndentConf): IndentConf
1617
local IndentConf = class(BaseConf, function(self, conf)
1718
local default_conf = {
@@ -21,6 +22,7 @@ local IndentConf = class(BaseConf, function(self, conf)
2122
chars = { "" },
2223
ahead_lines = 5,
2324
delay = 100,
25+
filter_list = {},
2426
}
2527
conf = vim.tbl_deep_extend("force", default_conf, conf or {}) --[[@as IndentConf]]
2628
BaseConf.init(self, conf)
@@ -31,6 +33,7 @@ local IndentConf = class(BaseConf, function(self, conf)
3133
self.chars = conf.chars
3234
self.ahead_lines = conf.ahead_lines
3335
self.delay = conf.delay
36+
self.filter_list = conf.filter_list
3437
end)
3538

3639
return IndentConf

lua/hlchunk/mods/indent/init.lua

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ local ROWS_INDENT_RETCODE = indentHelper.ROWS_INDENT_RETCODE
1313

1414
---@class IndentMetaInfo : MetaInfo
1515
---@field pre_leftcol number
16-
---@field cache Cache
1716

1817
local constructor = function(self, conf, meta)
1918
local default_meta = {
@@ -24,24 +23,29 @@ local constructor = function(self, conf, meta)
2423
shiftwidth = fn.shiftwidth(),
2524
pre_leftcol = 0,
2625
leftcol = fn.winsaveview().leftcol,
27-
cache = Cache("bufnr", "line"),
2826
}
2927

3028
BaseMod.init(self, conf, meta)
3129
self.meta = vim.tbl_deep_extend("force", default_meta, meta or {})
3230
self.conf = IndentConf(conf)
3331
end
3432

33+
---@class RenderInfo
34+
---@field lnum number
35+
---@field virt_text_win_col number
36+
---@field virt_text table
37+
---@field level number
38+
3539
---@class IndentMod : BaseMod
3640
---@field conf IndentConf
3741
---@field meta IndentMetaInfo
3842
---@field render fun(self: IndentMod, range: Scope, opts: {lazy: boolean})
39-
---@field narrowRange fun(self: IndentMod, range: Scope): Scope
40-
---@field calcRenderInfo fun(self: IndentMod, range: Scope): table<number, string>
43+
---@field calcRenderInfo fun(self: IndentMod, range: Scope): RenderInfo
4144
---@field setmark function
4245
---@overload fun(conf?: UserIndentConf, meta?: MetaInfo): IndentMod
4346
local IndentMod = class(BaseMod, constructor)
4447

48+
local indent_cache = Cache("bufnr", "line")
4549
local pos2info = Cache("bufnr", "line", "col")
4650
local pos2id = Cache("bufnr", "line", "col")
4751

@@ -51,17 +55,17 @@ function IndentMod:disable()
5155
BaseMod.disable(self)
5256
end
5357

54-
function IndentMod:narrowRange(range)
58+
local function narrowRange(range)
5559
local start = range.start
5660
local finish = range.finish
5761
for i = start, finish do
58-
if not self.meta.cache:has(range.bufnr, i) then
62+
if not indent_cache:has(range.bufnr, i) then
5963
start = i
6064
break
6165
end
6266
end
6367
for i = finish, start, -1 do
64-
if not self.meta.cache:has(range.bufnr, i) then
68+
if not indent_cache:has(range.bufnr, i) then
6569
finish = i
6670
break
6771
end
@@ -70,7 +74,6 @@ function IndentMod:narrowRange(range)
7074
end
7175

7276
function IndentMod:calcRenderInfo(range)
73-
-- calc render info
7477
local conf = self.conf
7578
local meta = self.meta
7679
local char_num = #conf.chars
@@ -79,7 +82,7 @@ function IndentMod:calcRenderInfo(range)
7982
local sw = meta.shiftwidth
8083
local render_info = {}
8184
for lnum = range.start, range.finish do
82-
local blankLen = meta.cache:get(range.bufnr, lnum) --[[@as string]]
85+
local blankLen = indent_cache:get(range.bufnr, lnum) --[[@as string]]
8386
local render_char_num, offset, shadow_char_num = indentHelper.calc(blankLen, leftcol, sw)
8487
for i = 1, render_char_num do
8588
local win_col = offset + (i - 1) * sw
@@ -89,8 +92,8 @@ function IndentMod:calcRenderInfo(range)
8992
lnum = lnum,
9093
virt_text_win_col = win_col,
9194
virt_text = { { char, style } },
95+
level = i,
9296
})
93-
pos2info:set(range.bufnr, lnum, win_col, { char, style })
9497
end
9598
end
9699

@@ -118,16 +121,17 @@ function IndentMod:render(range, opts)
118121
opts = opts or { lazy = false }
119122
local bufnr = range.bufnr
120123
local conf = self.conf
121-
local meta = self.meta
122124

123125
if not opts.lazy then
124-
self:clear(Scope(bufnr, 0, api.nvim_buf_line_count(bufnr)))
125-
meta.cache:clear(bufnr)
126-
pos2id:clear(bufnr)
127-
pos2info:clear(bufnr)
126+
self:clear(range)
127+
for i = range.start, range.finish do
128+
indent_cache:clear(bufnr, i)
129+
pos2id:clear(bufnr, i)
130+
pos2info:clear(bufnr, i)
131+
end
128132
end
129133

130-
local narrowed_range = self:narrowRange(range)
134+
local narrowed_range = narrowRange(range)
131135
local retcode, rows_indent = indentHelper.get_rows_indent(narrowed_range, {
132136
use_treesitter = conf.use_treesitter,
133137
virt_indent = true,
@@ -139,10 +143,19 @@ function IndentMod:render(range, opts)
139143
return
140144
end
141145

146+
-- get render_info and process it
142147
for lnum, indent in pairs(rows_indent) do
143-
meta.cache:set(bufnr, lnum, indent)
148+
indent_cache:set(bufnr, lnum, indent)
144149
end
145150
local render_info = self:calcRenderInfo(narrowed_range)
151+
for _, v in pairs(render_info) do
152+
pos2info:set(range.bufnr, v.lnum, v.virt_text_win_col, v.virt_text)
153+
end
154+
for _, filter in ipairs(self.conf.filter_list) do
155+
render_info = vim.tbl_filter(filter, render_info)
156+
end
157+
158+
-- render
146159
self:setmark(bufnr, render_info)
147160
end
148161

@@ -151,17 +164,18 @@ function IndentMod:createAutocmd()
151164
local render_cb = function(event, opts)
152165
opts = opts or { lazy = false }
153166
local bufnr = event.buf
154-
if not (api.nvim_buf_is_valid(bufnr) and self:shouldRender(bufnr)) then
167+
if not self:shouldRender(bufnr) then
155168
return
156169
end
157170
local wins = fn.win_findbuf(bufnr) or {}
158171
for _, winid in ipairs(wins) do
159-
local range = Scope(api.nvim_win_get_buf(winid), fn.line("w0", winid) - 1, fn.line("w$", winid) - 1)
172+
local win_bufnr = api.nvim_win_get_buf(winid)
173+
local range = Scope(win_bufnr, fn.line("w0", winid) - 1, fn.line("w$", winid) - 1)
160174
local ahead_lines = self.conf.ahead_lines
161175
range.start = math.max(0, range.start - ahead_lines)
162-
range.finish = math.min(api.nvim_buf_line_count(bufnr) - 1, range.finish + ahead_lines)
176+
range.finish = math.min(api.nvim_buf_line_count(win_bufnr) - 1, range.finish + ahead_lines)
163177
api.nvim_win_call(winid, function()
164-
self.meta.shiftwidth = cFunc.get_sw(bufnr)
178+
self.meta.shiftwidth = cFunc.get_sw(win_bufnr)
165179
self.meta.pre_leftcol = self.meta.leftcol
166180
self.meta.leftcol = fn.winsaveview().leftcol
167181
if self.meta.pre_leftcol ~= self.meta.leftcol then
@@ -187,16 +201,12 @@ function IndentMod:createAutocmd()
187201
throttle_render_cb_with_pre_hook(e, { lazy = true })
188202
end,
189203
})
190-
api.nvim_create_autocmd({ "TextChanged", "TextChangedI" }, {
204+
api.nvim_create_autocmd({ "TextChanged", "TextChangedI", "BufWinEnter" }, {
191205
group = self.meta.augroup_name,
192206
callback = function(e)
193207
throttle_render_cb_with_pre_hook(e, { lazy = false })
194208
end,
195209
})
196-
api.nvim_create_autocmd({ "BufWinEnter" }, {
197-
group = self.meta.augroup_name,
198-
callback = throttle_render_cb_with_pre_hook,
199-
})
200210
api.nvim_create_autocmd({ "OptionSet" }, {
201211
group = self.meta.augroup_name,
202212
pattern = "list,listchars,shiftwidth,tabstop,expandtab",

lua/hlchunk/utils/cache.lua

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ local Cache = class(function(self, ...)
99
self.cache = {}
1010
end)
1111

12-
local function navigateCache(cache, values, createIfMissing, setValue)
12+
local function navigateCache(cache, values, createIfMissing, isSetValue, setValue)
1313
local tableRef = cache
1414
local searchSteps = #values
1515
for i = 1, searchSteps - 1 do
@@ -24,9 +24,8 @@ local function navigateCache(cache, values, createIfMissing, setValue)
2424
tableRef = tableRef[key]
2525
end
2626

27-
if setValue then
27+
if isSetValue then
2828
tableRef[values[searchSteps]] = setValue
29-
return setValue
3029
else
3130
return tableRef[values[searchSteps]]
3231
end
@@ -46,7 +45,7 @@ function Cache:set(...)
4645
error("The number of keys passed to set() must be one more than the number of keys passed to the constructor")
4746
end
4847
local value = table.remove(values) -- 将最后一个参数作为要设置的值
49-
navigateCache(self.cache, values, true, value)
48+
navigateCache(self.cache, values, true, true, value)
5049
end
5150

5251
function Cache:has(...)
@@ -62,8 +61,16 @@ function Cache:clear(...)
6261
if #values == 0 then
6362
self.cache = {}
6463
else
65-
navigateCache(self.cache, values, false, {})
64+
navigateCache(self.cache, values, false, true, {})
6665
end
6766
end
6867

68+
function Cache:remove(...)
69+
local values = { ... }
70+
if #values ~= #self.keys then
71+
error("The number of keys passed to remove() must match the number of keys passed to the constructor")
72+
end
73+
navigateCache(self.cache, values, false, true, nil)
74+
end
75+
6976
return Cache

lua/hlchunk/utils/filetype.lua

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ M.exclude_filetypes = {
1212
mason = true,
1313
NvimTree = true,
1414
["neo-tree"] = true,
15+
["neo-tree-popup"] = true,
1516
plugin = true,
1617
lazy = true,
1718
TelescopePrompt = true,
@@ -48,6 +49,7 @@ M.exclude_filetypes = {
4849
startify = true,
4950
oil = true,
5051
glowpreview = true,
52+
fzf = true,
5153
}
5254

5355
return M

lua/hlchunk/utils/timer.lua

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,30 @@ function M.debounce(fn, delay, first)
6666
end
6767
end
6868

69+
function M.debounce_throttle(fn, delay)
70+
local timer = nil
71+
local called = false
72+
73+
return function(...)
74+
local args = { ... }
75+
if timer then
76+
timer:stop()
77+
end
78+
79+
if not called then
80+
fn(unpack(args))
81+
called = true
82+
M.setTimeout(function()
83+
called = false
84+
end, delay)
85+
else
86+
timer = M.setTimeout(function()
87+
fn(unpack(args))
88+
end, delay)
89+
end
90+
end
91+
end
92+
6993
---throttle function, assume we call a throttled func every 300ms for 9 times, and interval set to 1000ms
7094
---then will actually call 3 times, and timeline as follow:
7195
---`0ms` 300ms 600ms 900ms call throttled func, 0ms will tigger the timer, other 3 will be ignored

test/features/cache_spec.lua

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,15 @@ describe("cache", function()
6868
assert.equal(nil, cache:get(0, 0, 0))
6969
assert.equal(nil, cache:get(1, 0, 0))
7070
end)
71+
it("cache remove", function()
72+
local cache = Cache("bufnr", "line", "col")
73+
cache:set(0, 0, 0, "a")
74+
cache:set(0, 0, 1, "b")
75+
cache:set(0, 1, 0, "c")
76+
77+
cache:remove(0, 0, 0)
78+
assert.equal(nil, cache:get(0, 0, 0))
79+
assert.equal("b", cache:get(0, 0, 1))
80+
assert.equal("c", cache:get(0, 1, 0))
81+
end)
7182
end)

0 commit comments

Comments
 (0)