highlight.lua (1716B)
1 local M = { 2 style_ids = {} 3 } 4 5 local longest_keyword_length = 0 6 local lpeg_pattern 7 vis.events.subscribe(vis.events.INIT, function() 8 local keywords = M.keywords 9 for tag, style in pairs(keywords) do 10 M.style_ids[tag] = vis.ui:style_push(style) 11 if #tag > longest_keyword_length then 12 longest_keyword_length = #tag 13 end 14 end 15 16 local lpeg = vis.lpeg 17 -- TODO: can't this be done better? 18 local words 19 for tag, _ in pairs(keywords) do 20 if words then 21 words = words + lpeg.P(tag) 22 else 23 words = lpeg.P(tag) 24 end 25 end 26 if not words then return end 27 local cap = (1 - words)^0 * (lpeg.Cp() * words * lpeg.Cp()) 28 lpeg_pattern = lpeg.Ct(cap * ((1 - words) * cap)^0) 29 end) 30 31 local get_keywords = function(data) 32 local i, kwt, kws = 1, {}, lpeg_pattern:match(data) 33 if kws then 34 repeat 35 local kw = data:sub(kws[i], kws[i + 1] - 1) 36 table.insert(kwt, {kw, kws[i] - 1, kws[i + 1] - 2}) 37 i = i + 2 38 until (i > #kws) 39 end 40 return kwt 41 end 42 43 local last_data, last_tokens 44 vis.events.subscribe(vis.events.WIN_HIGHLIGHT, function(win) 45 local viewport = win.viewport.bytes 46 if not viewport then return end 47 local horizon_max = longest_keyword_length 48 local horizon = viewport.start < horizon_max and viewport.start or horizon_max 49 local lex_start = viewport.start - horizon 50 viewport.start = lex_start 51 52 local data = win.file:content(viewport) 53 local tokens = last_tokens 54 if last_data ~= data then 55 tokens = get_keywords(data) 56 last_tokens = tokens; 57 last_data = data 58 end 59 60 local style_ids = M.style_ids 61 for _, matches in pairs(tokens) do 62 local style_id = style_ids[matches[1]] 63 if style_id then 64 win:style(style_id, lex_start + matches[2], lex_start + matches[3]) 65 end 66 end 67 end) 68 69 return M