1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
local treesitter = {}
---@type table<string, blink.cmp.DrawHighlight[]>
local cache = {}
local cache_size = 0
local MAX_CACHE_SIZE = 1000
--- @param ctx blink.cmp.DrawItemContext
--- @param opts? {offset?: number}
function treesitter.highlight(ctx, opts)
local ret = cache[ctx.label]
if not ret then
-- cleanup cache if it's too big
cache_size = cache_size + 1
if cache_size > MAX_CACHE_SIZE then
cache = {}
cache_size = 0
end
ret = treesitter._highlight(ctx)
cache[ctx.label] = ret
end
-- offset highlights if needed
if opts and opts.offset then
ret = vim.deepcopy(ret)
for _, hl in ipairs(ret) do
hl[1] = hl[1] + opts.offset
hl[2] = hl[2] + opts.offset
end
end
return ret
end
--- @param ctx blink.cmp.DrawItemContext
function treesitter._highlight(ctx)
local ret = {} ---@type blink.cmp.DrawHighlight[]
local source = ctx.label
local lang = vim.treesitter.language.get_lang(vim.bo.filetype)
if not lang then return ret end
local ok, parser = pcall(vim.treesitter.get_string_parser, source, lang)
if not ok then return ret end
parser:parse(true)
parser:for_each_tree(function(tstree, tree)
if not tstree then return end
local query = vim.treesitter.query.get(tree:lang(), 'highlights')
-- Some injected languages may not have highlight queries.
if not query then return end
for capture, node in query:iter_captures(tstree:root(), source) do
local _, start_col, _, end_col = node:range()
---@type string
local name = query.captures[capture]
if name ~= 'spell' then
ret[#ret + 1] = {
start_col,
end_col,
group = '@' .. name .. '.' .. lang,
}
end
end
end)
return ret
end
return treesitter
|