Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions news/changelog-1.9.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,4 @@ All changes included in 1.9:
- ([#13998](https://github.com/quarto-dev/quarto-cli/issues/13998)): Fix YAML validation error with CR-only line terminators (old Mac format). Documents using `\r` line endings no longer fail with "Expected YAML front matter to contain at least 2 lines".
- ([#14012](https://github.com/quarto-dev/quarto-cli/issues/14012)): Add `fr-CA` language translation for Quebec French inclusive writing conventions, using parenthetical forms instead of middle dots for author labels. (author: @tdhock)
- ([#14032](https://github.com/quarto-dev/quarto-cli/issues/14032)): Add `editor_options` with `chunk_output_type` to YAML schema for autocompletion and validation in RStudio and Positron.
- ([#14156](https://github.com/quarto-dev/quarto-cli/issues/14156)): Avoid O(n^2) performance in handling large code blocks.
327 changes: 177 additions & 150 deletions src/resources/filters/quarto-pre/engine-escape.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,38 @@
local patterns = require("modules/patterns")

function engine_escape()
-- Line-by-line replacement for the pattern (\n?[^`\n]+`+){({+([^<}]+)}+)}
-- which suffers from O(n^2) backtracking on long lines without backticks.
-- See https://github.com/quarto-dev/quarto-cli/issues/14156
--
-- The original pattern cannot cross newlines (due to [^`\n]+), so processing
-- per-line is semantically equivalent and avoids catastrophic backtracking.
local line_pattern = "([^`\n]+`+)" .. patterns.engine_escape
local function unescape_inline_engine_codes(text)
if not text:find("{{", 1, true) then
return text
end
local result = {}
local pos = 1
local len = #text
while pos <= len do
local nl = text:find("\n", pos, true)
local line
if nl then
line = text:sub(pos, nl)
pos = nl + 1
else
line = text:sub(pos)
pos = len + 1
end
if line:find("`", 1, true) and line:find("{{", 1, true) then
line = line:gsub(line_pattern, "%1%2")
end
result[#result + 1] = line
end
return table.concat(result)
end

return {
CodeBlock = function(el)

Expand All @@ -26,7 +58,7 @@ function engine_escape()
end)

-- handles escaped inline code cells within a code block
el.text = el.text:gsub("(\n?[^`\n]+`+)" .. patterns.engine_escape, "%1%2")
el.text = unescape_inline_engine_codes(el.text)
return el
end,

Expand All @@ -46,156 +78,151 @@ end

-- FIXME these should be determined dynamically
local kHighlightClasses = {
"abc",
"actionscript",
"ada",
"agda",
"apache",
"asn1",
"asp",
"ats",
"awk",
"bash",
"bibtex",
"boo",
"c",
"changelog",
"clojure",
"cmake",
"coffee",
"coldfusion",
"comments",
"commonlisp",
"cpp",
"cs",
"css",
"curry",
"d",
"default",
"diff",
"djangotemplate",
"dockerfile",
"dot",
"doxygen",
"doxygenlua",
"dtd",
"eiffel",
"elixir",
"elm",
"email",
"erlang",
"fasm",
"fortranfixed",
"fortranfree",
"fsharp",
"gap",
"gcc",
"glsl",
"gnuassembler",
"go",
"graphql",
"groovy",
"hamlet",
"haskell",
"haxe",
"html",
"idris",
"ini",
"isocpp",
"j",
"java",
"javadoc",
"javascript",
"javascriptreact",
"json",
"jsp",
"julia",
"kotlin",
"latex",
"lex",
"lilypond",
"literatecurry",
"literatehaskell",
"llvm",
"lua",
"m4",
"makefile",
"mandoc",
"markdown",
"mathematica",
"matlab",
"maxima",
"mediawiki",
"metafont",
"mips",
"modelines",
"modula2",
"modula3",
"monobasic",
"mustache",
"nasm",
"nim",
"noweb",
"objectivec",
"objectivecpp",
"ocaml",
"octave",
"opencl",
"pascal",
"perl",
"php",
"pike",
"postscript",
"povray",
"powershell",
"prolog",
"protobuf",
"pure",
"purebasic",
"python",
"qml",
"r",
"raku",
"relaxng",
"relaxngcompact",
"rest",
"rhtml",
"roff",
"ruby",
"rust",
"scala",
"scheme",
"sci",
"sed",
"sgml",
"sml",
"spdxcomments",
"sql",
"sqlmysql",
"sqlpostgresql",
"stata",
"swift",
"tcl",
"tcsh",
"texinfo",
"toml",
"typescript",
"verilog",
"vhdl",
"xml",
"xorg",
"xslt",
"xul",
"yacc",
"yaml",
"zsh"
["abc"] = true,
["actionscript"] = true,
["ada"] = true,
["agda"] = true,
["apache"] = true,
["asn1"] = true,
["asp"] = true,
["ats"] = true,
["awk"] = true,
["bash"] = true,
["bibtex"] = true,
["boo"] = true,
["c"] = true,
["changelog"] = true,
["clojure"] = true,
["cmake"] = true,
["coffee"] = true,
["coldfusion"] = true,
["comments"] = true,
["commonlisp"] = true,
["cpp"] = true,
["cs"] = true,
["css"] = true,
["curry"] = true,
["d"] = true,
["default"] = true,
["diff"] = true,
["djangotemplate"] = true,
["dockerfile"] = true,
["dot"] = true,
["doxygen"] = true,
["doxygenlua"] = true,
["dtd"] = true,
["eiffel"] = true,
["elixir"] = true,
["elm"] = true,
["email"] = true,
["erlang"] = true,
["fasm"] = true,
["fortranfixed"] = true,
["fortranfree"] = true,
["fsharp"] = true,
["gap"] = true,
["gcc"] = true,
["glsl"] = true,
["gnuassembler"] = true,
["go"] = true,
["graphql"] = true,
["groovy"] = true,
["hamlet"] = true,
["haskell"] = true,
["haxe"] = true,
["html"] = true,
["idris"] = true,
["ini"] = true,
["isocpp"] = true,
["j"] = true,
["java"] = true,
["javadoc"] = true,
["javascript"] = true,
["javascriptreact"] = true,
["json"] = true,
["jsp"] = true,
["julia"] = true,
["kotlin"] = true,
["latex"] = true,
["lex"] = true,
["lilypond"] = true,
["literatecurry"] = true,
["literatehaskell"] = true,
["llvm"] = true,
["lua"] = true,
["m4"] = true,
["makefile"] = true,
["mandoc"] = true,
["markdown"] = true,
["mathematica"] = true,
["matlab"] = true,
["maxima"] = true,
["mediawiki"] = true,
["metafont"] = true,
["mips"] = true,
["modelines"] = true,
["modula2"] = true,
["modula3"] = true,
["monobasic"] = true,
["mustache"] = true,
["nasm"] = true,
["nim"] = true,
["noweb"] = true,
["objectivec"] = true,
["objectivecpp"] = true,
["ocaml"] = true,
["octave"] = true,
["opencl"] = true,
["pascal"] = true,
["perl"] = true,
["php"] = true,
["pike"] = true,
["postscript"] = true,
["povray"] = true,
["powershell"] = true,
["prolog"] = true,
["protobuf"] = true,
["pure"] = true,
["purebasic"] = true,
["python"] = true,
["qml"] = true,
["r"] = true,
["raku"] = true,
["relaxng"] = true,
["relaxngcompact"] = true,
["rest"] = true,
["rhtml"] = true,
["roff"] = true,
["ruby"] = true,
["rust"] = true,
["scala"] = true,
["scheme"] = true,
["sci"] = true,
["sed"] = true,
["sgml"] = true,
["sml"] = true,
["spdxcomments"] = true,
["sql"] = true,
["sqlmysql"] = true,
["sqlpostgresql"] = true,
["stata"] = true,
["swift"] = true,
["tcl"] = true,
["tcsh"] = true,
["texinfo"] = true,
["toml"] = true,
["typescript"] = true,
["verilog"] = true,
["vhdl"] = true,
["xml"] = true,
["xorg"] = true,
["xslt"] = true,
["xul"] = true,
["yacc"] = true,
["yaml"] = true,
["zsh"] = true
}

function isHighlightClass(class)
for _, v in ipairs (kHighlightClasses) do
if v == class then
return true
end
end
return false
if kHighlightClasses[class] then return true else return false end
end
Loading