aboutsummaryrefslogtreecommitdiff
path: root/lua
diff options
context:
space:
mode:
Diffstat (limited to 'lua')
-rw-r--r--lua/lexers/lexer.lua23
-rw-r--r--lua/vis-std.lua16
2 files changed, 32 insertions, 7 deletions
diff --git a/lua/lexers/lexer.lua b/lua/lexers/lexer.lua
index d4af90c..2973ea6 100644
--- a/lua/lexers/lexer.lua
+++ b/lua/lexers/lexer.lua
@@ -881,7 +881,7 @@ module('lexer')]=]
lpeg = require('lpeg')
local lpeg_P, lpeg_R, lpeg_S, lpeg_V = lpeg.P, lpeg.R, lpeg.S, lpeg.V
local lpeg_Ct, lpeg_Cc, lpeg_Cp = lpeg.Ct, lpeg.Cc, lpeg.Cp
-local lpeg_Cmt, lpeg_C = lpeg.Cmt, lpeg.C
+local lpeg_Cmt, lpeg_C, lpeg_Carg = lpeg.Cmt, lpeg.C, lpeg.Carg
local lpeg_match = lpeg.match
M.LEXERPATH = package.path
@@ -988,7 +988,13 @@ local function build_grammar(lexer, initial_rule)
lexer._INITIALRULE = initial_rule
lexer._GRAMMAR = lpeg_Ct(lpeg_P(grammar))
else
- lexer._GRAMMAR = lpeg_Ct(join_tokens(lexer)^0)
+ local function tmout(_, _, t1, redrawtime_max, flag)
+ if not redrawtime_max or os.clock() - t1 < redrawtime_max then return true end
+ if flag then flag.timedout = true end
+ end
+ local tokens = join_tokens(lexer)
+ -- every 500 tokens (approx. a screenful), check whether we have exceeded the timeout
+ lexer._GRAMMAR = lpeg_Ct((tokens * tokens^-500 * lpeg_Cmt(lpeg_Carg(1) * lpeg_Carg(2) * lpeg_Carg(3), tmout))^0)
end
end
@@ -1120,9 +1126,12 @@ end
-- @param text The text in the buffer to lex.
-- @param init_style The current style. Multiple-language lexers use this to
-- determine which language to start lexing in.
+-- @param redrawtime_max Stop lexing after that many seconds and set the second return value (timedout) to true.
+-- @param init Start lexing from this offset in *text* (default is 1).
-- @return table of token names and positions.
+-- @return whether the lexing timed out.
-- @name lex
-function M.lex(lexer, text, init_style)
+function M.lex(lexer, text, init_style, redrawtime_max, init)
if not lexer._GRAMMAR then return {M.DEFAULT, #text + 1} end
if not lexer._LEXBYLINE then
-- For multilang lexers, build a new grammar whose initial_rule is the
@@ -1138,7 +1147,8 @@ function M.lex(lexer, text, init_style)
end
end
end
- return lpeg_match(lexer._GRAMMAR, text)
+ local flag = {}
+ return lpeg_match(lexer._GRAMMAR, text, init, os.clock(), redrawtime_max, flag), flag.timedout
else
local tokens = {}
local function append(tokens, line_tokens, offset)
@@ -1149,8 +1159,9 @@ function M.lex(lexer, text, init_style)
end
local offset = 0
local grammar = lexer._GRAMMAR
+ local flag = {}
for line in text:gmatch('[^\r\n]*\r?\n?') do
- local line_tokens = lpeg_match(grammar, line)
+ local line_tokens = lpeg_match(grammar, line, init, os.clock(), redrawtime_max, flag)
if line_tokens then append(tokens, line_tokens, offset) end
offset = offset + #line
-- Use the default style to the end of the line if none was specified.
@@ -1158,7 +1169,7 @@ function M.lex(lexer, text, init_style)
tokens[#tokens + 1], tokens[#tokens + 2] = 'default', offset + 1
end
end
- return tokens
+ return tokens, flag.timedout
end
end
diff --git a/lua/vis-std.lua b/lua/vis-std.lua
index 31439c2..470872f 100644
--- a/lua/vis-std.lua
+++ b/lua/vis-std.lua
@@ -37,6 +37,17 @@ vis:option_register("horizon", "number", function(horizon)
return true
end, "Number of bytes to consider for syntax highlighting")
+vis:option_register("redrawtime", "string", function(redrawtime)
+ if not vis.win then return false end
+ local value = tonumber(redrawtime)
+ if not value or value <= 0 then
+ vis:info("A positive real number expected")
+ return false
+ end
+ vis.win.redrawtime = value
+ return true
+end, "Seconds to wait for syntax highlighting before aborting it")
+
vis.events.subscribe(vis.events.WIN_HIGHLIGHT, function(win)
if not win.syntax or not vis.lexers.load then return end
local lexer = vis.lexers.load(win.syntax, nil, true)
@@ -45,6 +56,7 @@ vis.events.subscribe(vis.events.WIN_HIGHLIGHT, function(win)
-- TODO: improve heuristic for initial style
local viewport = win.viewport
if not viewport then return end
+ local redrawtime_max = win.redrawtime or 1.0
local horizon_max = win.horizon or 32768
local horizon = viewport.start < horizon_max and viewport.start or horizon_max
local view_start = viewport.start
@@ -52,9 +64,11 @@ vis.events.subscribe(vis.events.WIN_HIGHLIGHT, function(win)
viewport.start = lex_start
local data = win.file:content(viewport)
local token_styles = lexer._TOKENSTYLES
- local tokens = lexer:lex(data, 1)
+ local tokens, timedout = lexer:lex(data, 1, redrawtime_max)
local token_end = lex_start + (tokens[#tokens] or 1) - 1
+ if timedout then return end
+
for i = #tokens - 1, 1, -2 do
local token_start = lex_start + (tokens[i-1] or 1) - 1
if token_end < view_start then