diff options
| author | Georgi Kirilov <in.the@repo> | 2020-02-17 14:42:24 +0200 |
|---|---|---|
| committer | Marc André Tanner <mat@brain-dump.org> | 2020-02-24 11:10:55 +0100 |
| commit | 15d213e4b6e33670cb50d472ad3f532245ebcc3b (patch) | |
| tree | 166e249426a946beb3b64b3653e99cde6f651153 | |
| parent | f63f26aac0be25b36959112af412773561daab5e (diff) | |
| download | vis-15d213e4b6e33670cb50d472ad3f532245ebcc3b.tar.gz vis-15d213e4b6e33670cb50d472ad3f532245ebcc3b.tar.xz | |
lua: add `redrawtime` option
Upper bound lexing time and cancel highlighting if it is exceeded.
| -rw-r--r-- | lua/lexers/lexer.lua | 23 | ||||
| -rw-r--r-- | lua/vis-std.lua | 16 | ||||
| -rw-r--r-- | man/vis.1 | 3 |
3 files changed, 35 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 @@ -1375,6 +1375,9 @@ Highlight a fixed column. .It Ic horizon Op Ar 32768 How many bytes back the lexer will look to synchronize parsing. . +.It Ic redrawtime Op Ar 1.0 +Maximum time (in seconds) to wait for syntax highlighting before aborting it. +. .It Ic theme Op Do default-16 Dc or Do default-256 Dc Color theme to use, name without file extension. . |
