|
3 | 3 |
|
4 | 4 | local patterns = require("modules/patterns") |
5 | 5 |
|
6 | | --- Line-by-line replacement for the pattern (\n?[^`\n]+`+){({+([^<}]+)}+)} |
7 | | --- which suffers from O(n^2) backtracking on long lines without backticks. |
8 | | --- See https://github.com/quarto-dev/quarto-cli/issues/14156 |
9 | | --- |
10 | | --- The original pattern cannot cross newlines (due to [^`\n]+), so processing |
11 | | --- per-line is semantically equivalent and avoids catastrophic backtracking. |
12 | | -local line_pattern = "([^`\n]+`+)" .. patterns.engine_escape |
13 | | -local function unescape_inline_engine_codes(text) |
14 | | - if not text:find("{{", 1, true) then |
15 | | - return text |
16 | | - end |
17 | | - local result = {} |
18 | | - local pos = 1 |
19 | | - local len = #text |
20 | | - while pos <= len do |
21 | | - local nl = text:find("\n", pos, true) |
22 | | - local line |
23 | | - if nl then |
24 | | - line = text:sub(pos, nl) |
25 | | - pos = nl + 1 |
26 | | - else |
27 | | - line = text:sub(pos) |
28 | | - pos = len + 1 |
| 6 | +function engine_escape() |
| 7 | + -- Line-by-line replacement for the pattern (\n?[^`\n]+`+){({+([^<}]+)}+)} |
| 8 | + -- which suffers from O(n^2) backtracking on long lines without backticks. |
| 9 | + -- See https://github.com/quarto-dev/quarto-cli/issues/14156 |
| 10 | + -- |
| 11 | + -- The original pattern cannot cross newlines (due to [^`\n]+), so processing |
| 12 | + -- per-line is semantically equivalent and avoids catastrophic backtracking. |
| 13 | + local line_pattern = "([^`\n]+`+)" .. patterns.engine_escape |
| 14 | + local function unescape_inline_engine_codes(text) |
| 15 | + if not text:find("{{", 1, true) then |
| 16 | + return text |
29 | 17 | end |
30 | | - if line:find("`", 1, true) and line:find("{{", 1, true) then |
31 | | - line = line:gsub(line_pattern, "%1%2") |
| 18 | + local result = {} |
| 19 | + local pos = 1 |
| 20 | + local len = #text |
| 21 | + while pos <= len do |
| 22 | + local nl = text:find("\n", pos, true) |
| 23 | + local line |
| 24 | + if nl then |
| 25 | + line = text:sub(pos, nl) |
| 26 | + pos = nl + 1 |
| 27 | + else |
| 28 | + line = text:sub(pos) |
| 29 | + pos = len + 1 |
| 30 | + end |
| 31 | + if line:find("`", 1, true) and line:find("{{", 1, true) then |
| 32 | + line = line:gsub(line_pattern, "%1%2") |
| 33 | + end |
| 34 | + result[#result + 1] = line |
32 | 35 | end |
33 | | - result[#result + 1] = line |
| 36 | + return table.concat(result) |
34 | 37 | end |
35 | | - return table.concat(result) |
36 | | -end |
37 | 38 |
|
38 | | -function engine_escape() |
39 | 39 | return { |
40 | 40 | CodeBlock = function(el) |
41 | 41 |
|
|
0 commit comments