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