summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/luatex
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/luatex')
-rw-r--r--Master/texmf-dist/tex/luatex/luamplib/luamplib.lua1180
-rw-r--r--Master/texmf-dist/tex/luatex/luamplib/luamplib.sty100
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-fontspec-27c.sty16
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-fontspec-29c.sty16
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-fontspec-29e.sty16
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-ruby.sty18
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/lltjext.sty128
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/ltj-ivd_aj1.lua7
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/ltj-jfmglue.lua6
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/ltj-jfont.lua18
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/ltj-latex.sty103
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/ltj-pretreat.lua7
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/ltj-rmlgbm.lua22
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/ltj-ruby.lua368
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/ltjsarticle.cls2
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/ltjsbook.cls2
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/ltjskiyou.cls2
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/ltjspf.cls2
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/ltjsreport.cls2
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/luatexja.lua7
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/luatexja.sty2
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/patches/lltjcore.sty9
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/patches/lltjdefs.sty51
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/patches/lltjfont.sty319
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-array.sty25
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-footmisc.sty62
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-geometry.sty24
-rw-r--r--Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-siunitx.sty113
-rw-r--r--Master/texmf-dist/tex/luatex/luaxml/luaxml-cssquery.lua14
-rw-r--r--Master/texmf-dist/tex/luatex/luaxml/luaxml-domobject.lua95
-rw-r--r--Master/texmf-dist/tex/luatex/luaxml/luaxml-encodings.lua88
-rw-r--r--Master/texmf-dist/tex/luatex/luaxml/luaxml-mod-html.lua221
-rw-r--r--Master/texmf-dist/tex/luatex/luaxml/luaxml-namedentities.lua4167
-rw-r--r--Master/texmf-dist/tex/luatex/luaxml/luaxml-transform.lua13
-rw-r--r--Master/texmf-dist/tex/luatex/markdown/markdown-parser.lua8990
-rw-r--r--Master/texmf-dist/tex/luatex/markdown/markdown-tinyyaml.lua4
-rw-r--r--Master/texmf-dist/tex/luatex/markdown/markdown.lua8252
-rw-r--r--Master/texmf-dist/tex/luatex/nodetree/nodetree-embed.sty4
-rw-r--r--Master/texmf-dist/tex/luatex/nodetree/nodetree.lua33
-rw-r--r--Master/texmf-dist/tex/luatex/nodetree/nodetree.sty4
-rw-r--r--Master/texmf-dist/tex/luatex/nodetree/nodetree.tex2
-rw-r--r--Master/texmf-dist/tex/luatex/penlight/penlight.lua355
-rw-r--r--Master/texmf-dist/tex/luatex/penlight/penlight.sty6
-rw-r--r--Master/texmf-dist/tex/luatex/penlightplus/penlightplus.lua17
-rw-r--r--Master/texmf-dist/tex/luatex/penlightplus/penlightplus.sty16
45 files changed, 13269 insertions, 11639 deletions
diff --git a/Master/texmf-dist/tex/luatex/luamplib/luamplib.lua b/Master/texmf-dist/tex/luatex/luamplib/luamplib.lua
index e4fb642f562..972e36172fd 100644
--- a/Master/texmf-dist/tex/luatex/luamplib/luamplib.lua
+++ b/Master/texmf-dist/tex/luatex/luamplib/luamplib.lua
@@ -11,8 +11,8 @@
luatexbase.provides_module {
name = "luamplib",
- version = "2.31.1",
- date = "2024/05/24",
+ version = "2.34.5",
+ date = "2024/08/03",
description = "Lua package to typeset Metapost with LuaTeX's MPLib.",
}
@@ -45,7 +45,6 @@ local function termorlog (target, text, kind)
if kind == "Error" then error() end
end
end
-
local function warn (...) -- beware '%' symbol
termorlog("term and log", select("#",...) > 1 and format(...) or ...)
end
@@ -60,22 +59,19 @@ luamplib.showlog = luamplib.showlog or false
local tableconcat = table.concat
local tableinsert = table.insert
+local tableunpack = table.unpack
local texsprint = tex.sprint
local texgettoks = tex.gettoks
local texgetbox = tex.getbox
local texruntoks = tex.runtoks
-
if not texruntoks then
err("Your LuaTeX version is too old. Please upgrade it to the latest")
end
-
local is_defined = token.is_defined
local get_macro = token.get_macro
-
local mplib = require ('mplib')
local kpse = require ('kpse')
local lfs = require ('lfs')
-
local lfsattributes = lfs.attributes
local lfsisdir = lfs.isdir
local lfsmkdir = lfs.mkdir
@@ -86,7 +82,6 @@ local file = file or { }
local replacesuffix = file.replacesuffix or function(filename, suffix)
return (filename:gsub("%.[%a%d]+$","")) .. "." .. suffix
end
-
local is_writable = file.is_writable or function(name)
if lfsisdir(name) then
name = name .. "/_luam_plib_temp_file_"
@@ -105,11 +100,8 @@ local mk_full_path = lfs.mkdirp or lfs.mkdirs or function(path)
end
end
-local luamplibtime = kpse.find_file("luamplib.lua")
-luamplibtime = luamplibtime and lfsattributes(luamplibtime,"modification")
-
+local luamplibtime = lfsattributes(kpse.find_file"luamplib.lua", "modification")
local currenttime = os.time()
-
local outputdir, cachedir
if lfstouch then
for i,v in ipairs{'TEXMFVAR','TEXMF_OUTPUT_DIRECTORY','.','TEXMFOUTPUT'} do
@@ -146,7 +138,6 @@ function luamplib.getcachedir(dir)
end
end
end
-
local noneedtoreplace = {
["boxes.mp"] = true, -- ["format.mp"] = true,
["graph.mp"] = true, ["marith.mp"] = true, ["mfplain.mp"] = true,
@@ -164,7 +155,6 @@ local noneedtoreplace = {
["mp-tool.mpiv"] = true, ["mp-cont.mpiv"] = true,
}
luamplib.noneedtoreplace = noneedtoreplace
-
local function replaceformatmp(file,newfile,ofmodify)
local fh = ioopen(file,"r")
if not fh then return file end
@@ -182,12 +172,10 @@ local function replaceformatmp(file,newfile,ofmodify)
lfstouch(newfile,currenttime,ofmodify)
return newfile
end
-
local name_b = "%f[%a_]"
local name_e = "%f[^%a_]"
local btex_etex = name_b.."btex"..name_e.."%s*(.-)%s*"..name_b.."etex"..name_e
local verbatimtex_etex = name_b.."verbatimtex"..name_e.."%s*(.-)%s*"..name_b.."etex"..name_e
-
local function replaceinputmpfile (name,file)
local ofmodify = lfsattributes(file,"modification")
if not ofmodify then return file end
@@ -200,19 +188,15 @@ local function replaceinputmpfile (name,file)
return nf.size == 0 and file or newfile
end
end
-
if name == "format.mp" then return replaceformatmp(file,newfile,ofmodify) end
-
local fh = ioopen(file,"r")
if not fh then return file end
local data = fh:read("*all"); fh:close()
-
local count,cnt = 0,0
data, cnt = data:gsub(btex_etex, "btex %1 etex ") -- space
count = count + cnt
data, cnt = data:gsub(verbatimtex_etex, "verbatimtex %1 etex;") -- semicolon
count = count + cnt
-
if count == 0 then
noneedtoreplace[name] = true
fh = ioopen(newfile,"w");
@@ -222,7 +206,6 @@ local function replaceinputmpfile (name,file)
end
return file
end
-
fh = ioopen(newfile,"w")
if not fh then return file end
fh:write(data); fh:close()
@@ -238,12 +221,10 @@ do
end
mpkpse = kpse.new(arg[exe], "mpost")
end
-
local special_ftype = {
pfb = "type1 fonts",
enc = "enc files",
}
-
function luamplib.finder (name, mode, ftype)
if mode == "w" then
if name and name ~= "mpout.log" then
@@ -273,16 +254,14 @@ local preamble = [[
let normalfontsize = fontsize;
input %s ;
]]
-
local currentformat = "plain"
function luamplib.setformat (name)
currentformat = name
end
-
luamplib.codeinherit = false
local mplibinstances = {}
+luamplib.instances = mplibinstances
local has_instancename = false
-
local function reporterror (result, prevlog)
if not result then
err("no result object returned")
@@ -314,7 +293,7 @@ local function reporterror (result, prevlog)
return log
end
end
-
+if not math.initialseed then math.randomseed(currenttime) end
local function luamplibload (name)
local mpx = mplib.new {
ini_version = true,
@@ -329,7 +308,7 @@ local function luamplibload (name)
local preamble = tableconcat{
format(preamble, replacesuffix(name,"mp")),
luamplib.preambles.mplibcode,
- luamplib.legacy_verbatimtex and luamplib.preambles.legacyverbatimtex or "",
+ luamplib.legacyverbatimtex and luamplib.preambles.legacyverbatimtex or "",
luamplib.textextlabel and luamplib.preambles.textextlabel or "",
}
local result, log
@@ -341,7 +320,6 @@ local function luamplibload (name)
log = reporterror(result)
return mpx, result, log
end
-
local function process (data, instancename)
local currfmt
if instancename and instancename ~= "" then
@@ -352,7 +330,7 @@ local function process (data, instancename)
currentformat,
luamplib.numbersystem or "scaled",
tostring(luamplib.textextlabel),
- tostring(luamplib.legacy_verbatimtex),
+ tostring(luamplib.legacyverbatimtex),
}
has_instancename = false
end
@@ -373,8 +351,6 @@ local function process (data, instancename)
if log then
if result.fig then
converted = luamplib.convert(result)
- else
- info"No figure output. Maybe no beginfig/endfig"
end
end
else
@@ -384,20 +360,17 @@ local function process (data, instancename)
end
local pdfmode = tex.outputmode > 0
+
local catlatex = luatexbase.registernumber("catcodetable@latex")
local catat11 = luatexbase.registernumber("catcodetable@atletter")
-
local function run_tex_code (str, cat)
texruntoks(function() texsprint(cat or catlatex, str) end)
end
-
local texboxes = { globalid = 0, localid = 4096 }
local factor = 65536*(7227/7200)
-
local textext_fmt = 'image(addto currentpicture doublepath unitsquare \z
-xscaled %f yscaled %f shifted (0,-%f) \z
-withprescript "mplibtexboxid=%i:%f:%f")'
-
+ xscaled %f yscaled %f shifted (0,-%f) \z
+ withprescript "mplibtexboxid=%i:%f:%f")'
local function process_tex_text (str)
if str then
local global = (has_instancename or luamplib.globaltextext or luamplib.codeinherit)
@@ -409,8 +382,7 @@ local function process_tex_text (str)
else
local boxid = texboxes.globalid + 1
texboxes.globalid = boxid
- run_tex_code(format(
- [[\expandafter\newbox\csname luamplib.box.%s\endcsname]], boxid))
+ run_tex_code(format([[\expandafter\newbox\csname luamplib.box.%s\endcsname]], boxid))
tex_box_id = tex.getcount'allocationnumber'
end
run_tex_code(format("%s\\setbox%i\\hbox{%s}", global, tex_box_id, str))
@@ -436,7 +408,6 @@ local mplibcolorfmt = {
[[\color_select:n%s\endgroup]],
},
}
-
local colfmt = is_defined'color_select:n' and "l3color" or "xcolor"
if colfmt == "l3color" then
run_tex_code{
@@ -450,7 +421,6 @@ if colfmt == "l3color" then
}
end
local ccexplat = luatexbase.registernumber"luamplibcctabexplat"
-
local function process_color (str)
if str then
if not str:find("%b{}") then
@@ -501,14 +471,12 @@ end
local tex_code_pre_mplib = {}
luamplib.figid = 1
luamplib.in_the_fig = false
-
local function process_verbatimtex_prefig (str)
if str then
tex_code_pre_mplib[luamplib.figid] = str
end
return ""
end
-
local function process_verbatimtex_infig (str)
if str then
return format('special "postmplibverbtex=%s";', str)
@@ -530,7 +498,6 @@ local mp = mp
mp.mf_path_reset = mp.mf_path_reset or function() end
mp.mf_finish_saving_data = mp.mf_finish_saving_data or function() end
mp.report = mp.report or info
-
catcodes = catcodes or {}
local catcodes = catcodes
catcodes.numbers = catcodes.numbers or {}
@@ -559,7 +526,6 @@ local function mpprint(buffer,...)
end
end
end
-
function luamplib.runscript (code)
local id, str = code:match("(.-){(.*)}")
if id and str then
@@ -581,7 +547,7 @@ function luamplib.runscript (code)
return buffer
end
buffer = {}
- mpprint(buffer, table.unpack(res))
+ mpprint(buffer, tableunpack(res))
return tableconcat(buffer)
end
return ""
@@ -594,9 +560,7 @@ local function protecttexcontents (str)
:gsub("%zPerCent%z", "\\%%")
:gsub("%s+", " ")
end
-
-luamplib.legacy_verbatimtex = true
-
+luamplib.legacyverbatimtex = true
function luamplib.maketext (str, what)
if str and str ~= "" then
str = protecttexcontents(str)
@@ -605,7 +569,7 @@ function luamplib.maketext (str, what)
not str:find("\\begin%s*{document}") and
not str:find("\\documentstyle"..name_e) and
not str:find("\\usepackage"..name_e) then
- if luamplib.legacy_verbatimtex then
+ if luamplib.legacyverbatimtex then
if luamplib.in_the_fig then
return process_verbatimtex_infig(str)
else
@@ -623,10 +587,10 @@ function luamplib.maketext (str, what)
end
local function colorsplit (res)
- local t, tt = { }, res:gsub("[%[%]]",""):explode()
+ local t, tt = { }, res:gsub("[%[%]]","",2):explode()
local be = tt[1]:find"^%d" and 1 or 2
for i=be, #tt do
- if tt[i]:find"^%a" then break end
+ if not tonumber(tt[i]) then break end
t[#t+1] = tt[i]
end
return t
@@ -661,28 +625,21 @@ luamplib.shadecolor = function (str)
run_tex_code({
[[\color_export:nnN{]], str, [[}{backend}\mplib_@tempa]],
},ccexplat)
- local name = get_macro'mplib_@tempa':match'{(.-)}{.+}'
+ local name, value = get_macro'mplib_@tempa':match'{(.-)}{(.-)}'
local t, obj = res:explode()
if pdfmode then
- obj = t[1]:match"^/(.+)"
- if ltx.pdf and ltx.pdf.object_id then
- obj = format("%s 0 R", ltx.pdf.object_id(obj))
- else
- run_tex_code({
- [[\edef\mplib_@tempa{\pdf_object_ref:n{]], obj, "}}",
- },ccexplat)
- obj = get_macro'mplib_@tempa'
- end
+ obj = format("%s 0 R", ltx.pdf.object_id( t[1]:sub(2,-1) ))
else
obj = t[2]
end
- local value = t[3]:match"%[(.-)%]" or t[3]
- return format('(%s) withprescript"mplib_spotcolor=%s:%s"', value,obj,name)
+ return format('(1) withprescript"mplib_spotcolor=%s:%s:%s"', value,obj,name)
end
return colorsplit(res)
end
-local running = -1073741824
+local decimals = "%.%d+"
+local function rmzeros(str) return str:gsub("%.?0+$","") end
+
local emboldenfonts = { }
local function getemboldenwidth (curr, fakebold)
local width = emboldenfonts.width
@@ -715,13 +672,14 @@ local function getrulewhatsit (line, wd, ht, dp)
fmt = "pdf:content "..fmt
pl = node.new("whatsit","special")
end
- pl.data = fmt:format(line, 0, -dp, wd, ht+dp, "B")
+ pl.data = fmt:format(line, 0, -dp, wd, ht+dp, "B") :gsub(decimals,rmzeros)
local ss = node.new"glue"
node.setglue(ss, 0, 65536, 65536, 2, 2)
pl.next = ss
return pl
end
local function getrulemetric (box, curr, bp)
+ local running = -1073741824
local wd,ht,dp = curr.width, curr.height, curr.depth
wd = wd == running and box.width or wd
ht = ht == running and box.height or ht
@@ -773,16 +731,16 @@ local function embolden (box, curr, fakebold)
head, curr = node.remove(head, curr)
elseif curr.id == node.id"glyph" and curr.font > 0 then
local f = curr.font
- local i = emboldenfonts[f]
+ local key = format("%s:%s",f,fakebold)
+ local i = emboldenfonts[key]
if not i then
+ local ft = font.getfont(f) or font.getcopy(f)
if pdfmode then
- local ft = font.getcopy(f)
width = ft.size * fakebold / factor * 10
emboldenfonts.width = width
ft.mode, ft.width = 2, width
i = font.define(ft)
else
- local ft = font.getfont(f) or font.getcopy(f)
if ft.format ~= "opentype" and ft.format ~= "truetype" then
goto skip_type1
end
@@ -790,7 +748,7 @@ local function embolden (box, curr, fakebold)
name = format('%s;embolden=%s;',name,fakebold)
_, i = fonts.constructors.readanddefine(name,ft.size)
end
- emboldenfonts[f] = i
+ emboldenfonts[key] = i
end
curr.font = i
end
@@ -802,6 +760,9 @@ end
local function graphictextcolor (col, filldraw)
if col:find"^[%d%.:]+$" then
col = col:explode":"
+ for i=1,#col do
+ col[i] = format("%.3f", col[i])
+ end
if pdfmode then
local op = #col == 4 and "k" or #col == 3 and "rg" or "g"
col[#col+1] = filldraw == "fill" and op or op:upper()
@@ -824,6 +785,7 @@ end
luamplib.graphictext = function (text, fakebold, fc, dc)
local fmt = process_tex_text(text):sub(1,-2)
local id = tonumber(fmt:match"mplibtexboxid=(%d+):")
+ emboldenfonts.width = nil
local box = texgetbox(id)
box.head = embolden(box, box.head, fakebold)
local fill = graphictextcolor(fc,"fill")
@@ -975,7 +937,7 @@ function luamplib.glyph (f, c)
if not gid then return mperr"cannot get GID (glyph id)" end
local fac = 1000 / (shapedata.units or 1000)
local t = shapedata.glyphs[gid].segments
- if not t then return "image(fill fullcircle scaled 0;)" end
+ if not t then return "image()" end
for i,v in ipairs(t) do
if type(v) == "table" then
for ii,vv in ipairs(v) do
@@ -989,8 +951,8 @@ function luamplib.glyph (f, c)
return glyphimage(t, kind)
end
-local rulefmt = "mplibpic[%i]:=image(addto currentpicture contour \z
-unitsquare shifted - center unitsquare;) xscaled %f yscaled %f shifted (%f,%f);"
+local rulefmt = "mpliboutlinepic[%i]:=image(addto currentpicture contour \z
+ unitsquare shifted - center unitsquare;) xscaled %f yscaled %f shifted (%f,%f);"
local outline_horz, outline_vert
function outline_vert (res, box, curr, xshift, yshift)
local b2u = box.dir == "LTL"
@@ -1108,6 +1070,18 @@ function outline_horz (res, box, curr, xshift, yshift, discwd)
dx = dx - (r2l and curr.width/factor*expand or 0)
local xpos = dx + xshift + (curr.xoffset or 0)/factor
local ypos = yshift + (curr.yoffset or 0)/factor
+ local vertical = ft.shared and ft.shared.features.vertical and "rotated 90" or ""
+ if vertical ~= "" then -- luatexko
+ for _,v in ipairs(ft.characters[curr.char].commands or { }) do
+ if v[1] == "down" then
+ ypos = ypos - v[2] / factor
+ elseif v[1] == "right" then
+ xpos = xpos + v[2] / factor
+ else
+ break
+ end
+ end
+ end
local image
if ft.format == "opentype" or ft.format == "truetype" then
image = luamplib.glyph(curr.font, gid)
@@ -1127,8 +1101,8 @@ function outline_horz (res, box, curr, xshift, yshift, discwd)
end
image = format("glyph %s of %q scaled %f", gid, name, scale)
end
- res[#res+1] = format("mplibpic[%i]:=%s xscaled %f yscaled %f slanted %f shifted (%f,%f);",
- #res+1, image, xscale, yscale, slant, xpos, ypos)
+ res[#res+1] = format("mpliboutlinepic[%i]:=%s xscaled %f yscaled %f slanted %f %s shifted (%f,%f);",
+ #res+1, image, xscale, yscale, slant, vertical, xpos, ypos)
dx = dx + (r2l and 0 or curr.width/factor*expand)
elseif curr.replace then
local width = node.dimensions(curr.replace)/factor
@@ -1213,12 +1187,8 @@ function luamplib.outlinetext (text)
local id = tonumber(fmt:match"mplibtexboxid=(%d+):")
local box = texgetbox(id)
local res = outline_horz({ }, box, box.head, 0, 0)
- if #res == 0 then res = { "mplibpic[1]:=image(fill fullcircle scaled 0;);" } end
- local t = { }
- for i=1, #res do
- t[#t+1] = format("addto currentpicture also mplibpic[%i];", i)
- end
- return tableconcat(res) .. format("mplibpic[0]:=image(%s);", tableconcat(t))
+ if #res == 0 then res = { "mpliboutlinepic[1]:=image();" } end
+ return tableconcat(res) .. format("mpliboutlinenum:=%i;", #res)
end
luamplib.preambles = {
@@ -1322,6 +1292,9 @@ def mplib_do_outline_text_set_f (text f) text r =
def mplib_do_outline_options_f = f enddef;
def mplib_do_outline_options_r = r enddef;
enddef;
+def mplib_do_outline_text_set_u (text f) text r =
+ def mplib_do_outline_options_f = f enddef;
+enddef;
def mplib_do_outline_text_set_d (text d) text r =
def mplib_do_outline_options_d = d enddef;
def mplib_do_outline_options_r = r enddef;
@@ -1335,27 +1308,40 @@ def mplib_do_outline_text_set_n text r =
def mplib_do_outline_options_r = r enddef;
enddef;
def mplib_do_outline_text_set_p = enddef;
-def mplib_fill_outline_text (expr p) =
- i:=0;
- for item within p:
- i:=i+1;
- addto currentpicture contour pathpart item
- if i < length p: withpostscript "collect"; fi
+def mplib_fill_outline_text =
+ for n=1 upto mpliboutlinenum:
+ i:=0;
+ for item within mpliboutlinepic[n]:
+ i:=i+1;
+ fill pathpart item mplib_do_outline_options_f withpen pencircle scaled 0
+ if (n<mpliboutlinenum) or (i<length mpliboutlinepic[n]): withpostscript "collect"; fi
+ endfor
endfor
- mplib_do_outline_options_f;
enddef;
-def mplib_draw_outline_text (expr p) =
- i:=0;
- for item within p:
- i:=i+1;
- addto currentpicture doublepath pathpart item
- if i < length p: withpostscript "collect"; fi
+def mplib_draw_outline_text =
+ for n=1 upto mpliboutlinenum:
+ for item within mpliboutlinepic[n]:
+ draw pathpart item mplib_do_outline_options_d;
+ endfor
+ endfor
+enddef;
+def mplib_filldraw_outline_text =
+ for n=1 upto mpliboutlinenum:
+ i:=0;
+ for item within mpliboutlinepic[n]:
+ i:=i+1;
+ if (n<mpliboutlinenum) or (i<length mpliboutlinepic[n]):
+ fill pathpart item mplib_do_outline_options_f withpostscript "collect";
+ else:
+ draw pathpart item mplib_do_outline_options_f withpostscript "both";
+ fi
+ endfor
endfor
- mplib_do_outline_options_d;
enddef;
vardef mpliboutlinetext@# (expr t) text rest =
save kind; string kind; kind := str @#;
- save mplibpic, i; picture mplibpic[]; numeric i;
+ save i; numeric i;
+ picture mpliboutlinepic[]; numeric mpliboutlinenum;
def mplib_do_outline_options_d = enddef;
def mplib_do_outline_options_f = enddef;
def mplib_do_outline_options_r = enddef;
@@ -1363,31 +1349,120 @@ vardef mpliboutlinetext@# (expr t) text rest =
image ( addto currentpicture also image (
if kind = "f":
mplib_do_outline_text_set_f rest;
- def mplib_do_outline_options_d = withpen pencircle scaled 0 enddef;
- mplib_fill_outline_text (mplibpic0);
+ mplib_fill_outline_text;
elseif kind = "d":
mplib_do_outline_text_set_d rest;
- mplib_draw_outline_text (mplibpic0);
+ mplib_draw_outline_text;
elseif kind = "b":
mplib_do_outline_text_set_b rest;
- mplib_fill_outline_text (mplibpic0);
- mplib_draw_outline_text (mplibpic0);
+ mplib_fill_outline_text;
+ mplib_draw_outline_text;
elseif kind = "u":
- mplib_do_outline_text_set_f rest;
- mplib_fill_outline_text (mplibpic0);
+ mplib_do_outline_text_set_u rest;
+ mplib_filldraw_outline_text;
elseif kind = "r":
mplib_do_outline_text_set_r rest;
- mplib_draw_outline_text (mplibpic0);
- mplib_fill_outline_text (mplibpic0);
+ mplib_draw_outline_text;
+ mplib_fill_outline_text;
elseif kind = "p":
mplib_do_outline_text_set_p;
- mplib_draw_outline_text (mplibpic0);
+ mplib_draw_outline_text;
else:
mplib_do_outline_text_set_n rest;
- mplib_fill_outline_text (mplibpic0);
+ mplib_fill_outline_text;
fi;
) mplib_do_outline_options_r; )
enddef ;
+primarydef t withpattern p =
+ image(
+ if cycle t:
+ fill
+ else:
+ draw
+ fi
+ t withprescript "mplibpattern=" & if numeric p: decimal fi p; )
+enddef;
+vardef mplibtransformmatrix (text e) =
+ save t; transform t;
+ t = identity e;
+ runscript("luamplib.transformmatrix = {"
+ & decimal xxpart t & ","
+ & decimal yxpart t & ","
+ & decimal xypart t & ","
+ & decimal yypart t & ","
+ & decimal xpart t & ","
+ & decimal ypart t & ","
+ & "}");
+enddef;
+primarydef p withfademethod s =
+ if picture p:
+ image(
+ draw p;
+ draw center p withprescript "mplibfadestate=stop";
+ )
+ else:
+ p withprescript "mplibfadestate=stop"
+ fi
+ withprescript "mplibfadetype=" & s
+ withprescript "mplibfadebbox=" &
+ decimal (xpart llcorner p -1/4) & ":" &
+ decimal (ypart llcorner p -1/4) & ":" &
+ decimal (xpart urcorner p +1/4) & ":" &
+ decimal (ypart urcorner p +1/4)
+enddef;
+def withfadeopacity (expr a,b) =
+ withprescript "mplibfadeopacity=" &
+ decimal a & ":" &
+ decimal b
+enddef;
+def withfadevector (expr a,b) =
+ withprescript "mplibfadevector=" &
+ decimal xpart a & ":" &
+ decimal ypart a & ":" &
+ decimal xpart b & ":" &
+ decimal ypart b
+enddef;
+let withfadecenter = withfadevector;
+def withfaderadius (expr a,b) =
+ withprescript "mplibfaderadius=" &
+ decimal a & ":" &
+ decimal b
+enddef;
+def withfadebbox (expr a,b) =
+ withprescript "mplibfadebbox=" &
+ decimal xpart a & ":" &
+ decimal ypart a & ":" &
+ decimal xpart b & ":" &
+ decimal ypart b
+enddef;
+primarydef p asgroup s =
+ image(
+ draw center p
+ withprescript "mplibgroupbbox=" &
+ decimal (xpart llcorner p -1/4) & ":" &
+ decimal (ypart llcorner p -1/4) & ":" &
+ decimal (xpart urcorner p +1/4) & ":" &
+ decimal (ypart urcorner p +1/4)
+ withprescript "gr_state=start"
+ withprescript "gr_type=" & s;
+ draw p;
+ draw center p withprescript "gr_state=stop";
+ )
+enddef;
+def withgroupbbox (expr a,b) =
+ withprescript "mplibgroupbbox=" &
+ decimal xpart a & ":" &
+ decimal ypart a & ":" &
+ decimal xpart b & ":" &
+ decimal ypart b
+enddef;
+def withgroupname expr s =
+ withprescript "mplibgroupname=" & s
+enddef;
+def usemplibgroup primary s =
+ draw maketext("\usemplibgroup{" & s & "}")
+ shifted runscript("return luamplib.trgroupshifts['" & s & "']")
+enddef;
]],
legacyverbatimtex = [[
def specialVerbatimTeX (text t) = runscript("luamplibprefig{"&t&"}") enddef;
@@ -1413,7 +1488,6 @@ enddef;
}
luamplib.verbatiminput = false
-
local function protect_expansion (str)
if str then
str = str:gsub("\\","!!!Control!!!")
@@ -1424,7 +1498,6 @@ local function protect_expansion (str)
return format("\\unexpanded{%s}",str)
end
end
-
local function unprotect_expansion (str)
if str then
return str:gsub("!!!Control!!!", "\\")
@@ -1434,22 +1507,17 @@ local function unprotect_expansion (str)
:gsub("!!!RBrace!!!", "}")
end
end
-
luamplib.everymplib = setmetatable({ [""] = "" },{ __index = function(t) return t[""] end })
luamplib.everyendmplib = setmetatable({ [""] = "" },{ __index = function(t) return t[""] end })
-
function luamplib.process_mplibcode (data, instancename)
texboxes.localid = 4096
-
- if luamplib.legacy_verbatimtex then
+ if luamplib.legacyverbatimtex then
luamplib.figid, tex_code_pre_mplib = 1, {}
end
-
local everymplib = luamplib.everymplib[instancename]
local everyendmplib = luamplib.everyendmplib[instancename]
data = format("\n%s\n%s\n%s\n",everymplib, data, everyendmplib)
:gsub("\r","\n")
-
if luamplib.verbatiminput then
data = data:gsub("\\mpcolor%s+(.-%b{})","mplibcolor(\"%1\")")
:gsub("\\mpdim%s+(%b{})", "mplibdimen(\"%1\")")
@@ -1478,163 +1546,42 @@ function luamplib.process_mplibcode (data, instancename)
return format("verbatimtex %s etex", unprotect_expansion(str))
end)
end
-
process(data, instancename)
end
-local further_split_keys = {
- mplibtexboxid = true,
- sh_color_a = true,
- sh_color_b = true,
-}
local function script2table(s)
local t = {}
for _,i in ipairs(s:explode("\13+")) do
local k,v = i:match("(.-)=(.*)") -- v may contain = or empty.
if k and v and k ~= "" and not t[k] then
- if further_split_keys[k] or further_split_keys[k:sub(1,10)] then
- t[k] = v:explode(":")
- else
- t[k] = v
- end
+ t[k] = v
end
end
return t
end
-local function getobjects(result,figure,f)
- return figure:objects()
-end
-
-function luamplib.convert (result, flusher)
- luamplib.flush(result, flusher)
- return true -- done
-end
-
local figcontents = { post = { } }
local function put2output(a,...)
figcontents[#figcontents+1] = type(a) == "string" and format(a,...) or a
end
-
local function pdf_startfigure(n,llx,lly,urx,ury)
put2output("\\mplibstarttoPDF{%f}{%f}{%f}{%f}",llx,lly,urx,ury)
end
-
local function pdf_stopfigure()
put2output("\\mplibstoptoPDF")
end
-
-local function pdf_literalcode (fmt,...)
- put2output{-2, format(fmt,...)}
-end
-
-local function pdf_textfigure(font,size,text,width,height,depth)
- text = text:gsub(".",function(c)
- return format("\\hbox{\\char%i}",string.byte(c)) -- kerning happens in metapost : false
- end)
- put2output("\\mplibtextext{%s}{%f}{%s}{%s}{%s}",font,size,text,0,0)
-end
-
-local bend_tolerance = 131/65536
-
-local rx, sx, sy, ry, tx, ty, divider = 1, 0, 0, 1, 0, 0, 1
-
-local function pen_characteristics(object)
- local t = mplib.pen_info(object)
- rx, ry, sx, sy, tx, ty = t.rx, t.ry, t.sx, t.sy, t.tx, t.ty
- divider = sx*sy - rx*ry
- return not (sx==1 and rx==0 and ry==0 and sy==1 and tx==0 and ty==0), t.width
-end
-
-local function concat(px, py) -- no tx, ty here
- return (sy*px-ry*py)/divider,(sx*py-rx*px)/divider
-end
-
-local function curved(ith,pth)
- local d = pth.left_x - ith.right_x
- if abs(ith.right_x - ith.x_coord - d) <= bend_tolerance and abs(pth.x_coord - pth.left_x - d) <= bend_tolerance then
- d = pth.left_y - ith.right_y
- if abs(ith.right_y - ith.y_coord - d) <= bend_tolerance and abs(pth.y_coord - pth.left_y - d) <= bend_tolerance then
- return false
- end
- end
- return true
-end
-
-local function flushnormalpath(path,open)
- local pth, ith
- for i=1,#path do
- pth = path[i]
- if not ith then
- pdf_literalcode("%f %f m",pth.x_coord,pth.y_coord)
- elseif curved(ith,pth) then
- pdf_literalcode("%f %f %f %f %f %f c",ith.right_x,ith.right_y,pth.left_x,pth.left_y,pth.x_coord,pth.y_coord)
- else
- pdf_literalcode("%f %f l",pth.x_coord,pth.y_coord)
- end
- ith = pth
- end
- if not open then
- local one = path[1]
- if curved(pth,one) then
- pdf_literalcode("%f %f %f %f %f %f c",pth.right_x,pth.right_y,one.left_x,one.left_y,one.x_coord,one.y_coord )
- else
- pdf_literalcode("%f %f l",one.x_coord,one.y_coord)
- end
- elseif #path == 1 then -- special case .. draw point
- local one = path[1]
- pdf_literalcode("%f %f l",one.x_coord,one.y_coord)
- end
-end
-
-local function flushconcatpath(path,open)
- pdf_literalcode("%f %f %f %f %f %f cm", sx, rx, ry, sy, tx ,ty)
- local pth, ith
- for i=1,#path do
- pth = path[i]
- if not ith then
- pdf_literalcode("%f %f m",concat(pth.x_coord,pth.y_coord))
- elseif curved(ith,pth) then
- local a, b = concat(ith.right_x,ith.right_y)
- local c, d = concat(pth.left_x,pth.left_y)
- pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(pth.x_coord, pth.y_coord))
- else
- pdf_literalcode("%f %f l",concat(pth.x_coord, pth.y_coord))
- end
- ith = pth
- end
- if not open then
- local one = path[1]
- if curved(pth,one) then
- local a, b = concat(pth.right_x,pth.right_y)
- local c, d = concat(one.left_x,one.left_y)
- pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(one.x_coord, one.y_coord))
- else
- pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord))
- end
- elseif #path == 1 then -- special case .. draw point
- local one = path[1]
- pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord))
- end
-end
-
-local function start_pdf_code()
- if pdfmode then
- pdf_literalcode("q")
- else
- put2output"\\special{pdf:bcontent}"
- end
-end
-local function stop_pdf_code()
- if pdfmode then
- pdf_literalcode("Q")
- else
- put2output"\\special{pdf:econtent}"
- end
+local function pdf_literalcode (...)
+ put2output{ -2, format(...) :gsub(decimals,rmzeros) }
end
+local start_pdf_code = pdfmode
+ and function() pdf_literalcode"q" end
+ or function() put2output"\\special{pdf:bcontent}" end
+local stop_pdf_code = pdfmode
+ and function() pdf_literalcode"Q" end
+ or function() put2output"\\special{pdf:econtent}" end
local function put_tex_boxes (object,prescript)
- local box = prescript.mplibtexboxid
+ local box = prescript.mplibtexboxid:explode":"
local n,tw,th = box[1],tonumber(box[2]),tonumber(box[3])
if n and tw and th then
local op = object.path
@@ -1660,6 +1607,7 @@ end
local prev_override_color
local function do_preobj_CR(object,prescript)
+ if object.postscript == "collect" then return end
local override = prescript and prescript.mpliboverridecolor
if override then
if pdfmode then
@@ -1687,32 +1635,44 @@ end
local pdfmanagement = is_defined'pdfmanagement_add:nnn'
local pdfobjs, pdfetcs = {}, {}
pdfetcs.pgfextgs = "pgf@sys@addpdfresource@extgs@plain"
-
-local function update_pdfobjs (os)
- local on = pdfobjs[os]
+pdfetcs.pgfpattern = "pgf@sys@addpdfresource@patterns@plain"
+pdfetcs.pgfcolorspace = "pgf@sys@addpdfresource@colorspaces@plain"
+local function update_pdfobjs (os, stream)
+ local key = os
+ if stream then key = key..stream end
+ local on = pdfobjs[key]
if on then
return on,false
end
if pdfmode then
- on = pdf.immediateobj(os)
+ if stream then
+ on = pdf.immediateobj("stream",stream,os)
+ else
+ on = pdf.immediateobj(os)
+ end
else
on = pdfetcs.cnt or 1
- texsprint(format("\\special{pdf:obj @mplibpdfobj%s %s}",on,os))
+ if stream then
+ texsprint(format("\\special{pdf:stream @mplibpdfobj%s (%s) <<%s>>}",on,stream,os))
+ else
+ texsprint(format("\\special{pdf:obj @mplibpdfobj%s %s}",on,os))
+ end
pdfetcs.cnt = on + 1
end
- pdfobjs[os] = on
+ pdfobjs[key] = on
return on,true
end
-
+pdfetcs.resfmt = pdfmode and "%s 0 R" or "@mplibpdfobj%s"
if pdfmode then
pdfetcs.getpageres = pdf.getpageresources or function() return pdf.pageresources end
- pdfetcs.setpageres = pdf.setpageresources or function(s) pdf.pageresources = s end
- pdfetcs.initialize_resources = function (name)
+ local getpageres = pdfetcs.getpageres
+ local setpageres = pdf.setpageresources or function(s) pdf.pageresources = s end
+ local initialize_resources = function (name)
local tabname = format("%s_res",name)
pdfetcs[tabname] = { }
if luatexbase.callbacktypes.finish_pdffile then -- ltluatex
local obj = pdf.reserveobj()
- pdfetcs.setpageres(format("%s/%s %i 0 R", pdfetcs.getpageres() or "", name, obj))
+ setpageres(format("%s/%s %i 0 R", getpageres() or "", name, obj))
luatexbase.add_to_callback("finish_pdffile", function()
pdf.immediateobj(obj, format("<<%s>>", tableconcat(pdfetcs[tabname])))
end,
@@ -1720,20 +1680,38 @@ if pdfmode then
end
end
pdfetcs.fallback_update_resources = function (name, res)
+ local tabname = format("%s_res",name)
+ if not pdfetcs[tabname] then
+ initialize_resources(name)
+ end
if luatexbase.callbacktypes.finish_pdffile then
- local t = pdfetcs[format("%s_res",name)]
+ local t = pdfetcs[tabname]
t[#t+1] = res
else
- local tpr, n = pdfetcs.getpageres() or "", 0
+ local tpr, n = getpageres() or "", 0
tpr, n = tpr:gsub(format("/%s<<",name), "%1"..res)
if n == 0 then
tpr = format("%s/%s<<%s>>", tpr, name, res)
end
- pdfetcs.setpageres(tpr)
+ setpageres(tpr)
end
end
else
- texsprint("\\special{pdf:obj @MPlibTr<<>>}","\\special{pdf:obj @MPlibSh<<>>}")
+ texsprint {
+ "\\luamplibatfirstshipout{",
+ "\\special{pdf:obj @MPlibTr<<>>}",
+ "\\special{pdf:obj @MPlibSh<<>>}",
+ "\\special{pdf:obj @MPlibCS<<>>}",
+ "\\special{pdf:obj @MPlibPt<<>>}}",
+ }
+ pdfetcs.resadded = { }
+ pdfetcs.fallback_update_resources = function (name,res,obj)
+ texsprint{"\\special{pdf:put ", obj, " <<", res, ">>}"}
+ if not pdfetcs.resadded[name] then
+ texsprint{"\\luamplibateveryshipout{\\special{pdf:put @resources <</", name, " ", obj, ">>}}"}
+ pdfetcs.resadded[name] = obj
+ end
+ end
end
local transparancy_modes = { [0] = "Normal",
@@ -1743,28 +1721,19 @@ local transparancy_modes = { [0] = "Normal",
"Hue", "Saturation", "Color", "Luminosity",
"Compatible",
}
-
-local function update_tr_res(mode,opaq)
- if pdfetcs.pgfloaded == nil then
- pdfetcs.pgfloaded = is_defined(pdfetcs.pgfextgs)
- if pdfmode and not pdfmanagement and not pdfetcs.pgfloaded and not is_defined"TRP@list" then
- pdfetcs.initialize_resources"ExtGState"
- end
- end
- local os = format("<</BM /%s/ca %.3f/CA %.3f/AIS false>>",mode,opaq,opaq)
- local on, new = update_pdfobjs(os)
- if not new then return on end
+local function add_extgs_resources (on, new)
local key = format("MPlibTr%s", on)
- local val = format(pdfmode and "%s 0 R" or "@mplibpdfobj%s", on)
- if pdfmanagement then
- texsprint(ccexplat,
- format("\\pdfmanagement_add:nnn{Page/Resources/ExtGState}{%s}{%s}", key, val))
- else
- local tr = format("/%s %s", key, val)
- if pdfetcs.pgfloaded then
- texsprint(format("\\csname %s\\endcsname{%s}", pdfetcs.pgfextgs,tr))
- elseif pdfmode then
- if is_defined"TRP@list" then
+ if new then
+ local val = format(pdfetcs.resfmt, on)
+ if pdfmanagement then
+ texsprint {
+ "\\csname pdfmanagement_add:nnn\\endcsname{Page/Resources/ExtGState}{", key, "}{", val, "}"
+ }
+ else
+ local tr = format("/%s %s", key, val)
+ if is_defined(pdfetcs.pgfextgs) then
+ texsprint { "\\csname ", pdfetcs.pgfextgs, "\\endcsname{", tr, "}" }
+ elseif is_defined"TRP@list" then
texsprint(catat11,{
[[\if@filesw\immediate\write\@auxout{]],
[[\string\g@addto@macro\string\TRP@list{]],
@@ -1775,82 +1744,87 @@ local function update_tr_res(mode,opaq)
texsprint(catat11,[[\global\TRP@reruntrue]])
end
else
- pdfetcs.fallback_update_resources("ExtGState", tr)
+ pdfetcs.fallback_update_resources("ExtGState",tr,"@MPlibTr")
end
- else
- texsprint(format("\\special{pdf:put @MPlibTr<<%s>>}",tr))
- texsprint"\\special{pdf:put @resources<</ExtGState @MPlibTr>>}"
end
end
- return on
+ return key
end
-
-local function do_preobj_TR(prescript)
+local function do_preobj_TR(object,prescript)
+ if object.postscript == "collect" then return end
local opaq = prescript and prescript.tr_transparency
- local tron_no
if opaq then
+ local key, on, os, new
local mode = prescript.tr_alternative or 1
- mode = transparancy_modes[tonumber(mode)]
- tron_no = update_tr_res(mode, opaq)
- start_pdf_code()
- pdf_literalcode("/MPlibTr%i gs",tron_no)
+ mode = transparancy_modes[tonumber(mode)] or mode
+ opaq = format("%.3f", opaq) :gsub(decimals,rmzeros)
+ for i,v in ipairs{ {mode,opaq},{"Normal",1} } do
+ os = format("<</BM/%s/ca %s/CA %s/AIS false>>",v[1],v[2],v[2])
+ on, new = update_pdfobjs(os)
+ key = add_extgs_resources(on,new)
+ if i == 1 then
+ pdf_literalcode("/%s gs",key)
+ else
+ return format("/%s gs",key)
+ end
+ end
end
- return tron_no
end
local function sh_pdfpageresources(shtype,domain,colorspace,ca,cb,coordinates,steps,fractions)
- if pdfmode and not pdfmanagement and not pdfetcs.Shading_res then
- pdfetcs.initialize_resources"Shading"
+ for _,v in ipairs{ca,cb} do
+ for i,vv in ipairs(v) do
+ for ii,vvv in ipairs(vv) do
+ v[i][ii] = tonumber(vvv) and format("%.3f",vvv) or vvv
+ end
+ end
end
- local fun2fmt,os = "<</FunctionType 2/Domain [%s]/C0 [%s]/C1 [%s]/N 1>>"
+ local fun2fmt,os = "<</FunctionType 2/Domain[%s]/C0[%s]/C1[%s]/N 1>>"
if steps > 1 then
local list,bounds,encode = { },{ },{ }
for i=1,steps do
if i < steps then
- bounds[i] = fractions[i] or 1
+ bounds[i] = format("%.3f", fractions[i] or 1)
end
encode[2*i-1] = 0
encode[2*i] = 1
os = fun2fmt:format(domain,tableconcat(ca[i],' '),tableconcat(cb[i],' '))
- list[i] = format(pdfmode and "%s 0 R" or "@mplibpdfobj%s",update_pdfobjs(os))
+ :gsub(decimals,rmzeros)
+ list[i] = format(pdfetcs.resfmt, update_pdfobjs(os))
end
os = tableconcat {
"<</FunctionType 3",
- format("/Bounds [%s]", tableconcat(bounds,' ')),
- format("/Encode [%s]", tableconcat(encode,' ')),
- format("/Functions [%s]", tableconcat(list, ' ')),
- format("/Domain [%s]>>", domain),
- }
+ format("/Bounds[%s]", tableconcat(bounds,' ')),
+ format("/Encode[%s]", tableconcat(encode,' ')),
+ format("/Functions[%s]", tableconcat(list, ' ')),
+ format("/Domain[%s]>>", domain),
+ } :gsub(decimals,rmzeros)
else
os = fun2fmt:format(domain,tableconcat(ca[1],' '),tableconcat(cb[1],' '))
+ :gsub(decimals,rmzeros)
end
- local objref = format(pdfmode and "%s 0 R" or "@mplibpdfobj%s",update_pdfobjs(os))
+ local objref = format(pdfetcs.resfmt, update_pdfobjs(os))
os = tableconcat {
format("<</ShadingType %i", shtype),
format("/ColorSpace %s", colorspace),
format("/Function %s", objref),
- format("/Coords [%s]", coordinates),
- "/Extend [true true]/AntiAlias true>>",
- }
+ format("/Coords[%s]", coordinates),
+ "/Extend[true true]/AntiAlias true>>",
+ } :gsub(decimals,rmzeros)
local on, new = update_pdfobjs(os)
- if not new then return on end
- local key = format("MPlibSh%s", on)
- local val = format(pdfmode and "%s 0 R" or "@mplibpdfobj%s", on)
- if pdfmanagement then
- texsprint(ccexplat,
- format("\\pdfmanagement_add:nnn{Page/Resources/Shading}{%s}{%s}", key, val))
- else
- local res = format("/%s %s", key, val)
- if pdfmode then
- pdfetcs.fallback_update_resources("Shading", res)
+ if new then
+ local key, val = format("MPlibSh%s", on), format(pdfetcs.resfmt, on)
+ if pdfmanagement then
+ texsprint {
+ "\\csname pdfmanagement_add:nnn\\endcsname{Page/Resources/Shading}{", key, "}{", val, "}"
+ }
else
- texsprint(format("\\special{pdf:put @MPlibSh<<%s>>}", res))
- texsprint"\\special{pdf:put @resources<</Shading @MPlibSh>>}"
+ local res = format("/%s %s", key, val)
+ pdfetcs.fallback_update_resources("Shading",res,"@MPlibSh")
end
end
return on
end
-
local function color_normalize(ca,cb)
if #cb == 1 then
if #ca == 4 then
@@ -1862,7 +1836,6 @@ local function color_normalize(ca,cb)
cb[1], cb[2], cb[3], cb[4] = 1-cb[1], 1-cb[2], 1-cb[3], 0
end
end
-
pdfetcs.clrspcs = setmetatable({ }, { __index = function(t,names)
run_tex_code({
[[\color_model_new:nnn]],
@@ -1874,20 +1847,21 @@ pdfetcs.clrspcs = setmetatable({ }, { __index = function(t,names)
t[names] = colorspace
return colorspace
end })
-
local function do_preobj_SH(object,prescript)
local shade_no
local sh_type = prescript and prescript.sh_type
- if sh_type then
+ if not sh_type then
+ return
+ else
local domain = prescript.sh_domain or "0 1"
- local centera = prescript.sh_center_a or "0 0"; centera = centera:explode()
- local centerb = prescript.sh_center_b or "0 0"; centerb = centerb:explode()
+ local centera = (prescript.sh_center_a or "0 0"):explode()
+ local centerb = (prescript.sh_center_b or "0 0"):explode()
local transform = prescript.sh_transform == "yes"
local sx,sy,sr,dx,dy = 1,1,1,0,0
if transform then
- local first = prescript.sh_first or "0 0"; first = first:explode()
- local setx = prescript.sh_set_x or "0 0"; setx = setx:explode()
- local sety = prescript.sh_set_y or "0 0"; sety = sety:explode()
+ local first = (prescript.sh_first or "0 0"):explode()
+ local setx = (prescript.sh_set_x or "0 0"):explode()
+ local sety = (prescript.sh_set_y or "0 0"):explode()
local x,y = tonumber(setx[1]) or 0, tonumber(sety[1]) or 0
if x ~= 0 and y ~= 0 then
local path = object.path
@@ -1909,15 +1883,15 @@ local function do_preobj_SH(object,prescript)
end
end
local ca, cb, colorspace, steps, fractions
- ca = { prescript.sh_color_a_1 or prescript.sh_color_a or {0} }
- cb = { prescript.sh_color_b_1 or prescript.sh_color_b or {1} }
+ ca = { (prescript.sh_color_a_1 or prescript.sh_color_a or "0"):explode":" }
+ cb = { (prescript.sh_color_b_1 or prescript.sh_color_b or "1"):explode":" }
steps = tonumber(prescript.sh_step) or 1
if steps > 1 then
fractions = { prescript.sh_fraction_1 or 0 }
for i=2,steps do
fractions[i] = prescript[format("sh_fraction_%i",i)] or (i/steps)
- ca[i] = prescript[format("sh_color_a_%i",i)] or {0}
- cb[i] = prescript[format("sh_color_b_%i",i)] or {1}
+ ca[i] = (prescript[format("sh_color_a_%i",i)] or "0"):explode":"
+ cb[i] = (prescript[format("sh_color_b_%i",i)] or "1"):explode":"
end
end
if prescript.mplib_spotcolor then
@@ -1926,15 +1900,14 @@ local function do_preobj_SH(object,prescript)
local script = object.prescript:explode"\13+"
for i=#script,1,-1 do
if script[i]:find"mplib_spotcolor" then
- local name, value
- objref, name = script[i]:match"=(.-):(.+)"
- value = script[i+1]:match"=(.+)"
+ local t, name, value = script[i]:explode"="[2]:explode":"
+ value, objref, name = t[1], t[2], t[3]
if not names[name] then
pos = pos+1
names[name] = pos
names[#names+1] = name
end
- local t = { }
+ t = { }
for j=1,names[name] do t[#t+1] = 0 end
t[#t+1] = value
tableinsert(#ca == #cb and ca or cb, t)
@@ -1985,11 +1958,489 @@ local function do_preobj_SH(object,prescript)
else
err"unknown shading type"
end
- pdf_literalcode("q /Pattern cs")
end
return shade_no
end
+pdfetcs.patterns = { }
+local function gather_resources (optres)
+ local t, do_pattern = { }, not optres
+ local names = {"ExtGState","ColorSpace","Shading"}
+ if do_pattern then
+ names[#names+1] = "Pattern"
+ end
+ if pdfmode then
+ if pdfmanagement then
+ for _,v in ipairs(names) do
+ local pp = get_macro(format("g__pdfdict_/g__pdf_Core/Page/Resources/%s_prop",v))
+ if pp and pp:find"__prop_pair" then
+ t[#t+1] = format("/%s %s 0 R", v, ltx.pdf.object_id("__pdf/Page/Resources/"..v))
+ end
+ end
+ else
+ local res = pdfetcs.getpageres() or ""
+ run_tex_code[[\mplibtmptoks\expandafter{\the\pdfvariable pageresources}]]
+ res = res .. texgettoks'mplibtmptoks'
+ if do_pattern then return res end
+ res = res:explode"/+"
+ for _,v in ipairs(res) do
+ v = v:match"^%s*(.-)%s*$"
+ if not v:find"Pattern" and not optres:find(v) then
+ t[#t+1] = "/" .. v
+ end
+ end
+ end
+ else
+ if pdfmanagement then
+ for _,v in ipairs(names) do
+ local pp = get_macro(format("g__pdfdict_/g__pdf_Core/Page/Resources/%s_prop",v))
+ if pp and pp:find"__prop_pair" then
+ run_tex_code {
+ "\\mplibtmptoks\\expanded{{",
+ format("/%s \\csname pdf_object_ref:n\\endcsname{__pdf/Page/Resources/%s}",v,v),
+ "}}",
+ }
+ t[#t+1] = texgettoks'mplibtmptoks'
+ end
+ end
+ elseif is_defined(pdfetcs.pgfextgs) then
+ run_tex_code ({
+ "\\mplibtmptoks\\expanded{{",
+ "\\ifpgf@sys@pdf@extgs@exists /ExtGState @pgfextgs\\fi",
+ "\\ifpgf@sys@pdf@colorspaces@exists /ColorSpace @pgfcolorspaces\\fi",
+ do_pattern and "\\ifpgf@sys@pdf@patterns@exists /Pattern @pgfpatterns \\fi" or "",
+ "}}",
+ }, catat11)
+ t[#t+1] = texgettoks'mplibtmptoks'
+ else
+ for _,v in ipairs(names) do
+ local vv = pdfetcs.resadded[v]
+ if vv then
+ t[#t+1] = format("/%s %s", v, vv)
+ end
+ end
+ end
+ end
+ return tableconcat(t)
+end
+function luamplib.registerpattern ( boxid, name, opts )
+ local box = texgetbox(boxid)
+ local wd = format("%.3f",box.width/factor)
+ local hd = format("%.3f",(box.height+box.depth)/factor)
+ info("w/h/d of pattern '%s': %s 0", name, format("%s %s",wd, hd):gsub(decimals,rmzeros))
+ if opts.xstep == 0 then opts.xstep = nil end
+ if opts.ystep == 0 then opts.ystep = nil end
+ if opts.colored == nil then
+ opts.colored = opts.coloured
+ if opts.colored == nil then
+ opts.colored = true
+ end
+ end
+ if type(opts.matrix) == "table" then opts.matrix = tableconcat(opts.matrix," ") end
+ if type(opts.bbox) == "table" then opts.bbox = tableconcat(opts.bbox," ") end
+ if opts.matrix and opts.matrix:find"%a" then
+ local data = format("mplibtransformmatrix(%s);",opts.matrix)
+ process(data,"@mplibtransformmatrix")
+ local t = luamplib.transformmatrix
+ opts.matrix = format("%f %f %f %f", t[1], t[2], t[3], t[4])
+ opts.xshift = opts.xshift or format("%f",t[5])
+ opts.yshift = opts.yshift or format("%f",t[6])
+ end
+ local attr = {
+ "/Type/Pattern",
+ "/PatternType 1",
+ format("/PaintType %i", opts.colored and 1 or 2),
+ "/TilingType 2",
+ format("/XStep %s", opts.xstep or wd),
+ format("/YStep %s", opts.ystep or hd),
+ format("/Matrix[%s %s %s]", opts.matrix or "1 0 0 1", opts.xshift or 0, opts.yshift or 0),
+ }
+ local optres = opts.resources or ""
+ optres = optres .. gather_resources(optres)
+ local patterns = pdfetcs.patterns
+ if pdfmode then
+ if opts.bbox then
+ attr[#attr+1] = format("/BBox[%s]", opts.bbox)
+ end
+ attr = tableconcat(attr) :gsub(decimals,rmzeros)
+ local index = tex.saveboxresource(boxid, attr, optres, true, opts.bbox and 4 or 1)
+ patterns[name] = { id = index, colored = opts.colored }
+ else
+ local cnt = #patterns + 1
+ local objname = "@mplibpattern" .. cnt
+ local metric = format("bbox %s", opts.bbox or format("0 0 %s %s",wd,hd))
+ texsprint {
+ "\\expandafter\\newbox\\csname luamplib.patternbox.", cnt, "\\endcsname",
+ "\\global\\setbox\\csname luamplib.patternbox.", cnt, "\\endcsname",
+ "\\hbox{\\unhbox ", boxid, "}\\luamplibatnextshipout{",
+ "\\special{pdf:bcontent}",
+ "\\special{pdf:bxobj ", objname, " ", metric, "}",
+ "\\raise\\dp\\csname luamplib.patternbox.", cnt, "\\endcsname",
+ "\\box\\csname luamplib.patternbox.", cnt, "\\endcsname",
+ "\\special{pdf:put @resources <<", optres, ">>}",
+ "\\special{pdf:exobj <<", tableconcat(attr), ">>}",
+ "\\special{pdf:econtent}}",
+ }
+ patterns[cnt] = objname
+ patterns[name] = { id = cnt, colored = opts.colored }
+ end
+end
+local function pattern_colorspace (cs)
+ local on, new = update_pdfobjs(format("[/Pattern %s]", cs))
+ if new then
+ local key, val = format("MPlibCS%i",on), format(pdfetcs.resfmt,on)
+ if pdfmanagement then
+ texsprint {
+ "\\csname pdfmanagement_add:nnn\\endcsname{Page/Resources/ColorSpace}{", key, "}{", val, "}"
+ }
+ else
+ local res = format("/%s %s", key, val)
+ if is_defined(pdfetcs.pgfcolorspace) then
+ texsprint { "\\csname ", pdfetcs.pgfcolorspace, "\\endcsname{", res, "}" }
+ else
+ pdfetcs.fallback_update_resources("ColorSpace",res,"@MPlibCS")
+ end
+ end
+ end
+ return on
+end
+local function do_preobj_PAT(object, prescript)
+ local name = prescript and prescript.mplibpattern
+ if not name then return end
+ local patterns = pdfetcs.patterns
+ local patt = patterns[name]
+ local index = patt and patt.id or err("cannot get pattern object '%s'", name)
+ local key = format("MPlibPt%s",index)
+ if patt.colored then
+ pdf_literalcode("/Pattern cs /%s scn", key)
+ else
+ local color = prescript.mpliboverridecolor
+ if not color then
+ local t = object.color
+ color = t and #t>0 and luamplib.colorconverter(t)
+ end
+ if not color then return end
+ local cs
+ if color:find" cs " or color:find"@pdf.obj" then
+ local t = color:explode()
+ if pdfmode then
+ cs = format("%s 0 R", ltx.pdf.object_id( t[1]:sub(2,-1) ))
+ color = t[3]
+ else
+ cs = t[2]
+ color = t[3]:match"%[(.+)%]"
+ end
+ else
+ local t = colorsplit(color)
+ cs = #t == 4 and "/DeviceCMYK" or #t == 3 and "/DeviceRGB" or "/DeviceGray"
+ color = tableconcat(t," ")
+ end
+ pdf_literalcode("/MPlibCS%i cs %s /%s scn", pattern_colorspace(cs), color, key)
+ end
+ if not patt.done then
+ local val = pdfmode and format("%s 0 R",index) or patterns[index]
+ if pdfmanagement then
+ texsprint {
+ "\\csname pdfmanagement_add:nnn\\endcsname{Page/Resources/Pattern}{", key, "}{", val, "}"
+ }
+ else
+ local res = format("/%s %s", key, val)
+ if is_defined(pdfetcs.pgfpattern) then
+ texsprint { "\\csname ", pdfetcs.pgfpattern, "\\endcsname{", res, "}" }
+ else
+ pdfetcs.fallback_update_resources("Pattern",res,"@MPlibPt")
+ end
+ end
+ end
+ patt.done = true
+end
+
+pdfetcs.fading = { }
+local function do_preobj_FADE (object, prescript)
+ local fd_type = prescript and prescript.mplibfadetype
+ local fd_stop = prescript and prescript.mplibfadestate
+ if not fd_type then
+ return fd_stop -- returns "stop" (if picture) or nil
+ end
+ local bbox = prescript.mplibfadebbox:explode":"
+ local dx, dy = -bbox[1], -bbox[2]
+ local vec = prescript.mplibfadevector; vec = vec and vec:explode":"
+ if not vec then
+ if fd_type == "linear" then
+ vec = {bbox[1], bbox[2], bbox[3], bbox[2]} -- left to right
+ else
+ local centerx, centery = (bbox[1]+bbox[3])/2, (bbox[2]+bbox[4])/2
+ vec = {centerx, centery, centerx, centery} -- center for both circles
+ end
+ end
+ local coords = { vec[1]+dx, vec[2]+dy, vec[3]+dx, vec[4]+dy }
+ if fd_type == "linear" then
+ coords = format("%f %f %f %f", tableunpack(coords))
+ elseif fd_type == "circular" then
+ local width, height = bbox[3]-bbox[1], bbox[4]-bbox[2]
+ local radius = (prescript.mplibfaderadius or "0:"..math.sqrt(width^2+height^2)/2):explode":"
+ tableinsert(coords, 3, radius[1])
+ tableinsert(coords, radius[2])
+ coords = format("%f %f %f %f %f %f", tableunpack(coords))
+ else
+ err("unknown fading method '%s'", fd_type)
+ end
+ fd_type = fd_type == "linear" and 2 or 3
+ local opaq = (prescript.mplibfadeopacity or "1:0"):explode":"
+ local on, os, new
+ on = sh_pdfpageresources(fd_type, "0 1", "/DeviceGray", {{opaq[1]}}, {{opaq[2]}}, coords, 1)
+ os = format("<</PatternType 2/Shading %s>>", format(pdfetcs.resfmt, on))
+ on = update_pdfobjs(os)
+ bbox = format("0 0 %f %f", bbox[3]+dx, bbox[4]+dy)
+ local streamtext = format("q /Pattern cs/MPlibFd%s scn %s re f Q", on, bbox)
+ :gsub(decimals,rmzeros)
+ os = format("<</Pattern<</MPlibFd%s %s>>>>", on, format(pdfetcs.resfmt, on))
+ on = update_pdfobjs(os)
+ local resources = format(pdfetcs.resfmt, on)
+ on = update_pdfobjs"<</S/Transparency/CS/DeviceGray>>"
+ local attr = tableconcat{
+ "/Subtype/Form",
+ "/BBox[", bbox, "]",
+ "/Matrix[1 0 0 1 ", format("%f %f", -dx,-dy), "]",
+ "/Resources ", resources,
+ "/Group ", format(pdfetcs.resfmt, on),
+ } :gsub(decimals,rmzeros)
+ on = update_pdfobjs(attr, streamtext)
+ os = "<</SMask<</S/Luminosity/G " .. format(pdfetcs.resfmt, on) .. ">>>>"
+ on, new = update_pdfobjs(os)
+ local key = add_extgs_resources(on,new)
+ start_pdf_code()
+ pdf_literalcode("/%s gs", key)
+ if fd_stop then return "standalone" end
+ return "start"
+end
+
+pdfetcs.tr_group = { shifts = { } }
+luamplib.trgroupshifts = pdfetcs.tr_group.shifts
+local function do_preobj_GRP (object, prescript)
+ local grstate = prescript and prescript.gr_state
+ if not grstate then return end
+ local trgroup = pdfetcs.tr_group
+ if grstate == "start" then
+ trgroup.name = prescript.mplibgroupname or "lastmplibgroup"
+ trgroup.isolated, trgroup.knockout = false, false
+ for _,v in ipairs(prescript.gr_type:explode",+") do
+ trgroup[v] = true
+ end
+ trgroup.bbox = prescript.mplibgroupbbox:explode":"
+ put2output[[\begingroup\setbox\mplibscratchbox\hbox\bgroup]]
+ elseif grstate == "stop" then
+ local llx,lly,urx,ury = tableunpack(trgroup.bbox)
+ put2output(tableconcat{
+ "\\egroup",
+ format("\\wd\\mplibscratchbox %fbp", urx-llx),
+ format("\\ht\\mplibscratchbox %fbp", ury-lly),
+ "\\dp\\mplibscratchbox 0pt",
+ })
+ local grattr = format("/Group<</S/Transparency/I %s/K %s>>",trgroup.isolated,trgroup.knockout)
+ local res = gather_resources()
+ local bbox = format("%f %f %f %f", llx,lly,urx,ury) :gsub(decimals,rmzeros)
+ if pdfmode then
+ put2output(tableconcat{
+ "\\saveboxresource type 2 attr{/Type/XObject/Subtype/Form/FormType 1",
+ "/BBox[", bbox, "]", grattr, "} resources{", res, "}\\mplibscratchbox",
+ [[\setbox\mplibscratchbox\hbox{\useboxresource\lastsavedboxresourceindex}]],
+ [[\wd\mplibscratchbox 0pt\ht\mplibscratchbox 0pt\dp\mplibscratchbox 0pt]],
+ [[\box\mplibscratchbox\endgroup]],
+ "\\expandafter\\xdef\\csname luamplib.group.", trgroup.name, "\\endcsname{",
+ "\\noexpand\\mplibstarttoPDF{",llx,"}{",lly,"}{",urx,"}{",ury,"}",
+ "\\useboxresource \\the\\lastsavedboxresourceindex\\noexpand\\mplibstoptoPDF}",
+ })
+ else
+ trgroup.cnt = (trgroup.cnt or 0) + 1
+ local objname = format("@mplibtrgr%s", trgroup.cnt)
+ put2output(tableconcat{
+ "\\special{pdf:bxobj ", objname, " bbox ", bbox, "}",
+ "\\unhbox\\mplibscratchbox",
+ "\\special{pdf:put @resources <<", res, ">>}",
+ "\\special{pdf:exobj <<", grattr, ">>}",
+ "\\special{pdf:uxobj ", objname, "}\\endgroup",
+ })
+ token.set_macro("luamplib.group."..trgroup.name, tableconcat{
+ "\\mplibstarttoPDF{",llx,"}{",lly,"}{",urx,"}{",ury,"}",
+ "\\special{pdf:uxobj ", objname, "}\\mplibstoptoPDF",
+ }, "global")
+ end
+ trgroup.shifts[trgroup.name] = { llx, lly }
+ end
+ return grstate
+end
+function luamplib.registergroup (boxid, name, opts)
+ local box = texgetbox(boxid)
+ local wd, ht, dp = node.getwhd(box)
+ local res = (opts.resources or "") .. gather_resources()
+ local attr = { "/Type/XObject/Subtype/Form/FormType 1" }
+ if type(opts.matrix) == "table" then opts.matrix = tableconcat(opts.matrix," ") end
+ if type(opts.bbox) == "table" then opts.bbox = tableconcat(opts.bbox," ") end
+ if opts.matrix and opts.matrix:find"%a" then
+ local data = format("mplibtransformmatrix(%s);",opts.matrix)
+ process(data,"@mplibtransformmatrix")
+ opts.matrix = format("%f %f %f %f %f %f",tableunpack(luamplib.transformmatrix))
+ end
+ local grtype = 3
+ if opts.bbox then
+ attr[#attr+1] = format("/BBox[%s]", opts.bbox)
+ grtype = 2
+ end
+ if opts.matrix then
+ attr[#attr+1] = format("/Matrix[%s]", opts.matrix)
+ grtype = opts.bbox and 4 or 1
+ end
+ if opts.asgroup then
+ local t = { isolated = false, knockout = false }
+ for _,v in ipairs(opts.asgroup:explode",+") do t[v] = true end
+ attr[#attr+1] = format("/Group<</S/Transparency/I %s/K %s>>", t.isolated, t.knockout)
+ end
+ local trgroup = pdfetcs.tr_group
+ trgroup.shifts[name] = { get_macro'MPllx', get_macro'MPlly' }
+ local whd
+ if pdfmode then
+ attr = tableconcat(attr) :gsub(decimals,rmzeros)
+ local index = tex.saveboxresource(boxid, attr, res, true, grtype)
+ token.set_macro("luamplib.group."..name, "\\useboxresource "..index, "global")
+ whd = format("%.3f %.3f 0", wd/factor, (ht+dp)/factor) :gsub(decimals,rmzeros)
+ else
+ trgroup.cnt = (trgroup.cnt or 0) + 1
+ local objname = format("@mplibtrgr%s", trgroup.cnt)
+ texsprint {
+ "\\expandafter\\newbox\\csname luamplib.groupbox.", trgroup.cnt, "\\endcsname",
+ "\\global\\setbox\\csname luamplib.groupbox.", trgroup.cnt, "\\endcsname",
+ "\\hbox{\\unhbox ", boxid, "}\\luamplibatnextshipout{",
+ "\\special{pdf:bcontent}",
+ "\\special{pdf:bxobj ", objname, " width ", wd, "sp height ", ht, "sp depth ", dp, "sp}",
+ "\\unhbox\\csname luamplib.groupbox.", trgroup.cnt, "\\endcsname",
+ "\\special{pdf:put @resources <<", res, ">>}",
+ "\\special{pdf:exobj <<", tableconcat(attr), ">>}",
+ "\\special{pdf:econtent}}",
+ }
+ token.set_macro("luamplib.group."..name, tableconcat{
+ "\\begingroup\\setbox\\mplibscratchbox\\hbox{\\special{pdf:uxobj ", objname, "}}",
+ "\\wd\\mplibscratchbox ", wd, "sp",
+ "\\ht\\mplibscratchbox ", ht, "sp",
+ "\\dp\\mplibscratchbox ", dp, "sp",
+ "\\box\\mplibscratchbox\\endgroup",
+ }, "global")
+ whd = format("%.3f %.3f %.3f", wd/factor, ht/factor, dp/factor) :gsub(decimals,rmzeros)
+ end
+ info("w/h/d of group '%s': %s", name, whd)
+end
+
+local function stop_special_effects(fade,opaq,over)
+ if fade then -- fading
+ stop_pdf_code()
+ end
+ if opaq then -- opacity
+ pdf_literalcode(opaq)
+ end
+ if over then -- color
+ put2output"\\special{pdf:ec}"
+ end
+end
+
+local function getobjects(result,figure,f)
+ return figure:objects()
+end
+
+function luamplib.convert (result, flusher)
+ luamplib.flush(result, flusher)
+ return true -- done
+end
+
+local function pdf_textfigure(font,size,text,width,height,depth)
+ text = text:gsub(".",function(c)
+ return format("\\hbox{\\char%i}",string.byte(c)) -- kerning happens in metapost : false
+ end)
+ put2output("\\mplibtextext{%s}{%f}{%s}{%s}{%s}",font,size,text,0,0)
+end
+
+local bend_tolerance = 131/65536
+
+local rx, sx, sy, ry, tx, ty, divider = 1, 0, 0, 1, 0, 0, 1
+
+local function pen_characteristics(object)
+ local t = mplib.pen_info(object)
+ rx, ry, sx, sy, tx, ty = t.rx, t.ry, t.sx, t.sy, t.tx, t.ty
+ divider = sx*sy - rx*ry
+ return not (sx==1 and rx==0 and ry==0 and sy==1 and tx==0 and ty==0), t.width
+end
+
+local function concat(px, py) -- no tx, ty here
+ return (sy*px-ry*py)/divider,(sx*py-rx*px)/divider
+end
+
+local function curved(ith,pth)
+ local d = pth.left_x - ith.right_x
+ if abs(ith.right_x - ith.x_coord - d) <= bend_tolerance and abs(pth.x_coord - pth.left_x - d) <= bend_tolerance then
+ d = pth.left_y - ith.right_y
+ if abs(ith.right_y - ith.y_coord - d) <= bend_tolerance and abs(pth.y_coord - pth.left_y - d) <= bend_tolerance then
+ return false
+ end
+ end
+ return true
+end
+
+local function flushnormalpath(path,open)
+ local pth, ith
+ for i=1,#path do
+ pth = path[i]
+ if not ith then
+ pdf_literalcode("%f %f m",pth.x_coord,pth.y_coord)
+ elseif curved(ith,pth) then
+ pdf_literalcode("%f %f %f %f %f %f c",ith.right_x,ith.right_y,pth.left_x,pth.left_y,pth.x_coord,pth.y_coord)
+ else
+ pdf_literalcode("%f %f l",pth.x_coord,pth.y_coord)
+ end
+ ith = pth
+ end
+ if not open then
+ local one = path[1]
+ if curved(pth,one) then
+ pdf_literalcode("%f %f %f %f %f %f c",pth.right_x,pth.right_y,one.left_x,one.left_y,one.x_coord,one.y_coord )
+ else
+ pdf_literalcode("%f %f l",one.x_coord,one.y_coord)
+ end
+ elseif #path == 1 then -- special case .. draw point
+ local one = path[1]
+ pdf_literalcode("%f %f l",one.x_coord,one.y_coord)
+ end
+end
+
+local function flushconcatpath(path,open)
+ pdf_literalcode("%f %f %f %f %f %f cm", sx, rx, ry, sy, tx ,ty)
+ local pth, ith
+ for i=1,#path do
+ pth = path[i]
+ if not ith then
+ pdf_literalcode("%f %f m",concat(pth.x_coord,pth.y_coord))
+ elseif curved(ith,pth) then
+ local a, b = concat(ith.right_x,ith.right_y)
+ local c, d = concat(pth.left_x,pth.left_y)
+ pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(pth.x_coord, pth.y_coord))
+ else
+ pdf_literalcode("%f %f l",concat(pth.x_coord, pth.y_coord))
+ end
+ ith = pth
+ end
+ if not open then
+ local one = path[1]
+ if curved(pth,one) then
+ local a, b = concat(pth.right_x,pth.right_y)
+ local c, d = concat(one.left_x,one.left_y)
+ pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(one.x_coord, one.y_coord))
+ else
+ pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord))
+ end
+ elseif #path == 1 then -- special case .. draw point
+ local one = path[1]
+ pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord))
+ end
+end
+
function luamplib.flush (result,flusher)
if result then
local figures = result.fig
@@ -2018,7 +2469,10 @@ function luamplib.flush (result,flusher)
local prescript = object.prescript
prescript = prescript and script2table(prescript) -- prescript is now a table
local cr_over = do_preobj_CR(object,prescript) -- color
- local tr_opaq = do_preobj_TR(prescript) -- opacity
+ local tr_opaq = do_preobj_TR(object,prescript) -- opacity
+ local fading_ = do_preobj_FADE(object,prescript) -- fading
+ local trgroup = do_preobj_GRP(object,prescript) -- transparency group
+ local pattern_ = do_preobj_PAT(object,prescript) -- pattern
if prescript and prescript.mplibtexboxid then
put_tex_boxes(object,prescript)
elseif objecttype == "start_bounds" or objecttype == "stop_bounds" then --skip
@@ -2040,7 +2494,7 @@ function luamplib.flush (result,flusher)
pdf_literalcode("%f %f %f %f %f %f cm",ot[3],ot[4],ot[5],ot[6],ot[1],ot[2])
pdf_textfigure(object.font,object.dsize,object.text,object.width,object.height,object.depth)
stop_pdf_code()
- else
+ elseif not trgroup and fading_ ~= "stop" then
local evenodd, collect, both = false, false, false
local postscript = object.postscript
if not object.istext then
@@ -2064,7 +2518,6 @@ function luamplib.flush (result,flusher)
savedhtap[#savedhtap+1] = object.htap or false
end
else
- local shade_no = do_preobj_SH(object,prescript) -- shading
local ml = object.miterlimit
if ml and ml ~= miterlimit then
miterlimit = ml
@@ -2106,6 +2559,11 @@ function luamplib.flush (result,flusher)
objecttype = 'fill'
end
end
+ local shade_no = do_preobj_SH(object,prescript) -- shading
+ if shade_no then
+ pdf_literalcode"q /Pattern cs"
+ objecttype = false
+ end
if transformed then
start_pdf_code()
end
@@ -2126,18 +2584,16 @@ function luamplib.flush (result,flusher)
else
flushnormalpath(path,open)
end
- if not shade_no then -- conflict with shading
- if objecttype == "fill" then
- pdf_literalcode(evenodd and "h f*" or "h f")
- elseif objecttype == "outline" then
- if both then
- pdf_literalcode(evenodd and "h B*" or "h B")
- else
- pdf_literalcode(open and "S" or "h S")
- end
- elseif objecttype == "both" then
+ if objecttype == "fill" then
+ pdf_literalcode(evenodd and "h f*" or "h f")
+ elseif objecttype == "outline" then
+ if both then
pdf_literalcode(evenodd and "h B*" or "h B")
+ else
+ pdf_literalcode(open and "S" or "h S")
end
+ elseif objecttype == "both" then
+ pdf_literalcode(evenodd and "h B*" or "h B")
end
end
if transformed then
@@ -2177,15 +2633,25 @@ function luamplib.flush (result,flusher)
end
end
if shade_no then -- shading
- pdf_literalcode("W n /MPlibSh%s sh Q",shade_no)
+ pdf_literalcode("W%s n /MPlibSh%s sh Q",evenodd and "*" or "",shade_no)
end
end
end
- if tr_opaq then -- opacity
- stop_pdf_code()
+ if fading_ == "start" then
+ pdfetcs.fading.specialeffects = {fading_, tr_opaq, cr_over}
+ elseif trgroup == "start" then
+ pdfetcs.tr_group.specialeffects = {fading_, tr_opaq, cr_over}
+ elseif fading_ == "stop" then
+ local se = pdfetcs.fading.specialeffects
+ if se then stop_special_effects(se[1], se[2], se[3]) end
+ elseif trgroup == "stop" then
+ local se = pdfetcs.tr_group.specialeffects
+ if se then stop_special_effects(se[1], se[2], se[3]) end
+ else
+ stop_special_effects(fading_, tr_opaq, cr_over)
end
- if cr_over then -- color
- put2output"\\special{pdf:ec}"
+ if fading_ or trgroup then -- extgs resetted
+ miterlimit, linecap, linejoin, dashed = -1, -1, -1, false
end
end
end
diff --git a/Master/texmf-dist/tex/luatex/luamplib/luamplib.sty b/Master/texmf-dist/tex/luatex/luamplib/luamplib.sty
index 6fa986d62bb..f305eacd4e0 100644
--- a/Master/texmf-dist/tex/luatex/luamplib/luamplib.sty
+++ b/Master/texmf-dist/tex/luatex/luamplib/luamplib.sty
@@ -8,15 +8,24 @@
%%
%% See source file 'luamplib.dtx' for licencing and contact information.
%%
-\bgroup\expandafter\expandafter\expandafter\egroup
-\expandafter\ifx\csname selectfont\endcsname\relax
- \input ltluatex
-\else
+\ifcsname ProvidesPackage\endcsname
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{luamplib}
- [2024/05/24 v2.31.1 mplib package for LuaTeX]
- \ifx\newluafunction\@undefined
+ [2024/08/03 v2.34.5 mplib package for LuaTeX]
+\fi
+\ifdefined\newluafunction\else
\input ltluatex
+\fi
+\ifnum\outputmode=0
+ \ifdefined\AddToHookNext
+ \def\luamplibatnextshipout{\AddToHookNext{shipout/background}}
+ \def\luamplibatfirstshipout{\AddToHook{shipout/firstpage}}
+ \def\luamplibateveryshipout{\AddToHook{shipout/background}}
+ \else
+ \input atbegshi.sty
+ \def\luamplibatnextshipout#1{\AtBeginShipoutNext{\AtBeginShipoutAddToBox{#1}}}
+ \let\luamplibatfirstshipout\AtBeginShipoutFirst
+ \def\luamplibateveryshipout#1{\AtBeginShipout{\AtBeginShipoutAddToBox{#1}}}
\fi
\fi
\directlua{require("luamplib")}
@@ -46,6 +55,69 @@
\catcode`\&=12 \catcode`\$=12 \catcode`\%=12 \catcode`\^^M=12
}
\def\mplibputtextbox#1{\vbox to 0pt{\vss\hbox to 0pt{\raise\dp#1\copy#1\hss}}}
+\protected\def\usemplibgroup#1{\csname luamplib.group.#1\endcsname}
+\protected\def\mplibgroup#1{%
+ \begingroup
+ \def\MPllx{0}\def\MPlly{0}%
+ \def\mplibgroupname{#1}%
+ \mplibgroupgetnexttok
+}
+\def\mplibgroupgetnexttok{\futurelet\nexttok\mplibgroupbranch}
+\def\mplibgroupskipspace{\afterassignment\mplibgroupgetnexttok\let\nexttok= }
+\def\mplibgroupbranch{%
+ \ifx [\nexttok
+ \expandafter\mplibgroupopts
+ \else
+ \ifx\mplibsptoken\nexttok
+ \expandafter\expandafter\expandafter\mplibgroupskipspace
+ \else
+ \let\mplibgroupoptions\empty
+ \expandafter\expandafter\expandafter\mplibgroupmain
+ \fi
+ \fi
+}
+\def\mplibgroupopts[#1]{\def\mplibgroupoptions{#1}\mplibgroupmain}
+\def\mplibgroupmain{\setbox\mplibscratchbox\hbox\bgroup\ignorespaces}
+\protected\def\endmplibgroup{\egroup
+ \directlua{ luamplib.registergroup(
+ \the\mplibscratchbox, '\mplibgroupname', {\mplibgroupoptions}
+ )}%
+ \endgroup
+}
+{\def\:{\global\let\mplibsptoken= } \: }
+\protected\def\mppattern#1{%
+ \begingroup
+ \def\mplibpatternname{#1}%
+ \mplibpatterngetnexttok
+}
+\def\mplibpatterngetnexttok{\futurelet\nexttok\mplibpatternbranch}
+\def\mplibpatternskipspace{\afterassignment\mplibpatterngetnexttok\let\nexttok= }
+\def\mplibpatternbranch{%
+ \ifx [\nexttok
+ \expandafter\mplibpatternopts
+ \else
+ \ifx\mplibsptoken\nexttok
+ \expandafter\expandafter\expandafter\mplibpatternskipspace
+ \else
+ \let\mplibpatternoptions\empty
+ \expandafter\expandafter\expandafter\mplibpatternmain
+ \fi
+ \fi
+}
+\def\mplibpatternopts[#1]{%
+ \def\mplibpatternoptions{#1}%
+ \mplibpatternmain
+}
+\def\mplibpatternmain{%
+ \setbox\mplibscratchbox\hbox\bgroup\ignorespaces
+}
+\protected\def\endmppattern{%
+ \egroup
+ \directlua{ luamplib.registerpattern(
+ \the\mplibscratchbox, '\mplibpatternname', {\mplibpatternoptions}
+ )}%
+ \endgroup
+}
\def\mpfiginstancename{@mpfig}
\protected\def\mpfig{%
\begingroup
@@ -66,16 +138,16 @@
\long\def\mplibdomainmpfig#1\endmpfig{%
\endgroup
\directlua{
- local legacy = luamplib.legacy_verbatimtex
+ local legacy = luamplib.legacyverbatimtex
local everympfig = luamplib.everymplib["\mpfiginstancename"] or ""
local everyendmpfig = luamplib.everyendmplib["\mpfiginstancename"] or ""
- luamplib.legacy_verbatimtex = false
+ luamplib.legacyverbatimtex = false
luamplib.everymplib["\mpfiginstancename"] = ""
luamplib.everyendmplib["\mpfiginstancename"] = ""
luamplib.process_mplibcode(
"beginfig(0) "..everympfig.." "..[===[\unexpanded{#1}]===].." "..everyendmpfig.." endfig;",
"\mpfiginstancename")
- luamplib.legacy_verbatimtex = legacy
+ luamplib.legacyverbatimtex = legacy
luamplib.everymplib["\mpfiginstancename"] = everympfig
luamplib.everyendmplib["\mpfiginstancename"] = everyendmpfig
}%
@@ -89,14 +161,14 @@
\long\def\mplibdoprempfig#1\endmpfig{%
\endgroup
\directlua{
- local legacy = luamplib.legacy_verbatimtex
+ local legacy = luamplib.legacyverbatimtex
local everympfig = luamplib.everymplib["\mpfiginstancename"]
local everyendmpfig = luamplib.everyendmplib["\mpfiginstancename"]
- luamplib.legacy_verbatimtex = false
+ luamplib.legacyverbatimtex = false
luamplib.everymplib["\mpfiginstancename"] = ""
luamplib.everyendmplib["\mpfiginstancename"] = ""
luamplib.process_mplibcode([===[\unexpanded{#1}]===],"\mpfiginstancename")
- luamplib.legacy_verbatimtex = legacy
+ luamplib.legacyverbatimtex = legacy
luamplib.everymplib["\mpfiginstancename"] = everympfig
luamplib.everyendmplib["\mpfiginstancename"] = everyendmpfig
}%
@@ -163,9 +235,9 @@
\def\mpliblegacybehavior#1{\directlua{
local s = string.lower("#1")
if s == "enable" or s == "true" or s == "yes" then
- luamplib.legacy_verbatimtex = true
+ luamplib.legacyverbatimtex = true
else
- luamplib.legacy_verbatimtex = false
+ luamplib.legacyverbatimtex = false
end
}}
\def\mplibverbatim#1{\directlua{
diff --git a/Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-fontspec-27c.sty b/Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-fontspec-27c.sty
index 76ebf8716c8..6ef3ff1751e 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-fontspec-27c.sty
+++ b/Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-fontspec-27c.sty
@@ -3,7 +3,7 @@
%
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{luatexja-fontspec-27c}[2024-02-19 fontspec support of LuaTeX-ja]
+\ProvidesPackage{luatexja-fontspec-27c}[2024-05-27 fontspec support of LuaTeX-ja]
\RequirePackage{l3keys2e}
\ExplSyntaxOn
@@ -359,10 +359,24 @@
\setfontfamily #1 [#2,#4] {#3}
\cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_orig_fontspec_set_family:Nnn
}
+\DeclareDocumentCommand \providejfontfamily { m O{} m O{} } {
+ \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_fontspec_set_family:Nnn
+ \providefontfamily #1 [#2,#4] {#3}
+ \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_orig_fontspec_set_family:Nnn
+}
\DeclareDocumentCommand \newjfontface { m O{} m O{} } {
\newjfontfamily #1 [ BoldFont={},ItalicFont={},SmallCapsFont={},#2,#4 ] {#3}
}
+\DeclareDocumentCommand \renewjfontface { m O{} m O{} } {
+ \renewjfontfamily #1 [ BoldFont={},ItalicFont={},SmallCapsFont={},#2,#4 ] {#3}
+}
+\DeclareDocumentCommand \setjfontface { m O{} m O{} } {
+ \setjfontfamily #1 [ BoldFont={},ItalicFont={},SmallCapsFont={},#2,#4 ] {#3}
+}
+\DeclareDocumentCommand \providejfontface { m O{} m O{} } {
+ \providejfontfamily #1 [ BoldFont={},ItalicFont={},SmallCapsFont={},#2,#4 ] {#3}
+}
\prop_new:N \l__ltj_fontspec_tmp_prop
\prop_new:N \g__ltj_fontspec_fontopts_prop
diff --git a/Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-fontspec-29c.sty b/Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-fontspec-29c.sty
index 1415cee1274..51af33447ce 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-fontspec-29c.sty
+++ b/Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-fontspec-29c.sty
@@ -3,7 +3,7 @@
%
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{luatexja-fontspec-29c}[2024-05-05 fontspec support of LuaTeX-ja]
+\ProvidesPackage{luatexja-fontspec-29c}[2024-05-27 fontspec support of LuaTeX-ja]
\RequirePackage{l3keys2e}
\ExplSyntaxOn
@@ -359,10 +359,24 @@
\setfontfamily #1 [#2,#4] {#3}
\cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_orig_fontspec_set_family:Nnn
}
+\DeclareDocumentCommand \providejfontfamily { m O{} m O{} } {
+ \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_fontspec_set_family:Nnn
+ \providefontfamily #1 [#2,#4] {#3}
+ \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_orig_fontspec_set_family:Nnn
+}
\DeclareDocumentCommand \newjfontface { m O{} m O{} } {
\newjfontfamily #1 [ BoldFont={},ItalicFont={},SmallCapsFont={},#2,#4 ] {#3}
}
+\DeclareDocumentCommand \renewjfontface { m O{} m O{} } {
+ \renewjfontfamily #1 [ BoldFont={},ItalicFont={},SmallCapsFont={},#2,#4 ] {#3}
+}
+\DeclareDocumentCommand \setjfontface { m O{} m O{} } {
+ \setjfontfamily #1 [ BoldFont={},ItalicFont={},SmallCapsFont={},#2,#4 ] {#3}
+}
+\DeclareDocumentCommand \providejfontface { m O{} m O{} } {
+ \providejfontfamily #1 [ BoldFont={},ItalicFont={},SmallCapsFont={},#2,#4 ] {#3}
+}
\prop_new:N \l__ltj_fontspec_tmp_prop
\prop_new:N \g__ltj_fontspec_fontopts_prop
diff --git a/Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-fontspec-29e.sty b/Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-fontspec-29e.sty
index e763d91ad7d..02a79ad6ca2 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-fontspec-29e.sty
+++ b/Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-fontspec-29e.sty
@@ -3,7 +3,7 @@
%
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{luatexja-fontspec-29e}[2024-05-14 fontspec support of LuaTeX-ja]
+\ProvidesPackage{luatexja-fontspec-29e}[2024-05-27 fontspec support of LuaTeX-ja]
\RequirePackage{l3keys2e}
\ExplSyntaxOn
@@ -359,10 +359,24 @@
\setfontfamily #1 [#2,#4] {#3}
\cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_orig_fontspec_set_family:Nnn
}
+\DeclareDocumentCommand \providejfontfamily { m O{} m O{} } {
+ \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_fontspec_set_family:Nnn
+ \providefontfamily #1 [#2,#4] {#3}
+ \cs_set_eq:NN \fontspec_set_family:Nnn \__ltj_orig_fontspec_set_family:Nnn
+}
\DeclareDocumentCommand \newjfontface { m O{} m O{} } {
\newjfontfamily #1 [ BoldFont={},ItalicFont={},SmallCapsFont={},#2,#4 ] {#3}
}
+\DeclareDocumentCommand \renewjfontface { m O{} m O{} } {
+ \renewjfontfamily #1 [ BoldFont={},ItalicFont={},SmallCapsFont={},#2,#4 ] {#3}
+}
+\DeclareDocumentCommand \setjfontface { m O{} m O{} } {
+ \setjfontfamily #1 [ BoldFont={},ItalicFont={},SmallCapsFont={},#2,#4 ] {#3}
+}
+\DeclareDocumentCommand \providejfontface { m O{} m O{} } {
+ \providejfontfamily #1 [ BoldFont={},ItalicFont={},SmallCapsFont={},#2,#4 ] {#3}
+}
\prop_new:N \l__ltj_fontspec_tmp_prop
\prop_new:N \g__ltj_fontspec_fontopts_prop
diff --git a/Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-ruby.sty b/Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-ruby.sty
index d0d8e5488dd..4c64b27d149 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-ruby.sty
+++ b/Master/texmf-dist/tex/luatex/luatexja/addons/luatexja-ruby.sty
@@ -4,7 +4,7 @@
% LaTeX only!
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{luatexja-ruby}[2023-10-08 v0.62]
+\ProvidesPackage{luatexja-ruby}[2024-09-09 v0.7]
\RequirePackage{luatexja}
%%------------------
@@ -18,9 +18,9 @@
%% 引数:ルビ全角を単位とした実数
%% この文字への pre-, post-intrusion の許容量
\define@key[ltj]{japaram}{rubypreintrusion}{%
- \ltj@@set@stack@real{RIPRE}{-0x7FFFFFFF}{0x7FFFFFFF}#1 }
+ \ltj@@set@stack@real{RIPRE}{-0x7FFFFFFF}{0x7FFFFFFF}#1\relax}
\define@key[ltj]{japaram}{rubypostintrusion}{%
- \ltj@@set@stack@real{RIPOST}{-0x7FFFFFFF}{0x7FFFFFFF}#1 }
+ \ltj@@set@stack@real{RIPOST}{-0x7FFFFFFF}{0x7FFFFFFF}#1\relax}
\def\ltj@@set@stack@real#1#2#3{%
\directlua{luatexja.stack.set_stack_perchar(luatexja.stack_table_index.#1,
#2, #3, token.scan_word)}}
@@ -29,7 +29,6 @@
\def\ltj@@rkeydef#1{
\define@key[ltj]{ruby}{#1}{\expandafter\def\csname ltj@@rubyip@#1\endcsname{##1}}
}
-%% attr_ruby_mode
%% bit 0: intrusion を有効にするか(1: 有効)
%% bit 1: 前後の intrusion 許容量を小さい方に揃える (1: yes)
%% bit 2--4: intrusion をどう使って親文字を配置するか
@@ -42,10 +41,10 @@
%% ※ 01--100 で,intrusion で賄えきれなかった場合はいつものように伸長する.
%% bit 5: 熟語ルビの際の処理方法(0: 常にグループ,1: 可能な限りブロックごとに)
%% ↑bit 5 は今は無効
+%% bit 6: 突出部分について lua-ul 有効範囲から除外する処理するか
\ltj@@rkeydef{mode}
%% intrusion 量強制固定(bit 0, bit 1 より優先,負数で「自動」)
%% attr は sp 単位だが,ユーザーはルビ全角単位で指定する
-%% attr_ruby_maxprep, attr_ruby_maxpostp
\ltj@@rkeydef{pre}
\ltj@@rkeydef{post}
%% 親文字伸長の際の比,{0}{1}{1} などと0--7 の数 3 つで指定
@@ -54,14 +53,11 @@
\ltj@@rkeydef{stretcheol} % 行末形
\ltj@@rkeydef{stretch} % 行中形
%% ルビが伸長するときの比 {1}{2}{1} などと0--7 の数 3 つで指定
-%% attr_ruby_mode 上位部分
\ltj@@rkeydef{stretchruby}
%% ルビ<親のとき,ルビと親文字の端の最大値
-%% attr_ruby_maxmargin
%% attr は sp 単位だが,ユーザーは親文字全角単位で指定
\ltj@@rkeydef{maxmargin}
%% ルビと親文字の垂直方向の空き
-%% attr_ruby_intergap
%% attr は sp 単位だが,ユーザーは親文字全角単位で指定
\ltj@@rkeydef{intergap}
@@ -92,6 +88,7 @@
\define@boolkey[ltj]{ruby}{intrude_xkanjiskip}[true]{}
\define@boolkey[ltj]{ruby}{intrude_kanjiskip}[true]{}
+\define@boolkey[ltj]{ruby}{always_highlight_protrusion}[true]{}
%%%%%%%% setkeys の別名
\protected\def\ltjsetruby{\setkeys[ltj]{ruby}}
@@ -141,7 +138,8 @@
[luatexja.icflag_table.XKANJI_SKIP]=true,
[luatexja.icflag_table.XKANJI_SKIP_JFM]=true,
\fi
- \string}
+ \string},
+ quirk_protrusion = \ifltj@ruby@always_highlight_protrusion false \else true \fi
\string}
}
\egroup
@@ -264,7 +262,7 @@
kenten=\textbullet, fontcmd=\relax, ybaseheight=0.88, tbaseheight=0.5,
yrubydepth=0.12, trubydepth=0.5,
intrude_jfmgk, intrude_kanjiskip, intrude_xkanjiskip,
- epsilon=0.0001,
+ epsilon=0.0001, always_highlight_protrusion=false,
}
\endinput
diff --git a/Master/texmf-dist/tex/luatex/luatexja/lltjext.sty b/Master/texmf-dist/tex/luatex/luatexja/lltjext.sty
index a83c9305c93..aebdc3987c5 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/lltjext.sty
+++ b/Master/texmf-dist/tex/luatex/luatexja/lltjext.sty
@@ -3,7 +3,7 @@
%
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{lltjext}[2022-08-24 v1.2k-ltj-14 Macros for vertical writing]
+\ProvidesPackage{lltjext}[2024-07-23 v1.2k-ltj-16 Macros for vertical writing]
\RequirePackage{luatexja}
\newcount\ltj@ext@dir
\let\ltj@lltjext@orig@tabular=\tabular
@@ -27,7 +27,7 @@
\def\p@stabular<#1>#2{%
\setlength\dimen@{#2}%
\edef\@halignto{to\the\dimen@}\p@tabular<#1>}
-\def\p@tabular<#1>{\leavevmode \hbox \bgroup
+\def\p@tabular<#1>{\leavevmode\null \hbox \bgroup % fixed for unwanted xkanjiskip
\ltj@ext@dir=\ltjgetparameter{direction}\relax
$\let\@acol\@tabacol
\let\@classz\@tabclassz
@@ -78,7 +78,7 @@
\ifhmode \@preamerr\z@ \@@par\fi
\@preamble}
\def\endarray{\crcr\egroup\egroup\@end@alignbox}
-\def\endtabular{\endarray$\egroup}
+\def\endtabular{\endarray$\egroup\null}
\expandafter \let \csname endtabular*\endcsname = \endtabular
% ↓中身\周囲→ yoko tate utod dtou
% yoko A* B* B B
@@ -541,17 +541,11 @@
\else \let\box@dir\utod
\fi
\fi
-\ifltj@ltfilehook@avail % LaTeX2e >= 2020-10-01
\@defaultunitsset\@picht{#3}\unitlength
\@defaultunitsset\@picwd{#2}\unitlength
\setbox\@picbox\hbox to\@picwd\bgroup\box@dir
\@defaultunitsset\@tempdimc{#4}\unitlength\hskip-\@tempdimc
\@defaultunitsset\@tempdimc{#5}\unitlength\lower\@tempdimc\hbox\bgroup
-\else % <= 2020-02-02
- \@picwd=#2\unitlength \@picht=#3\unitlength
- \setbox\@picbox\hbox to\@picwd\bgroup\box@dir
- \hskip-#4\unitlength\lower#5\unitlength\hbox\bgroup
-\fi
\ltj@@pic@reset@blshift
\ignorespaces}
\def\endpicture{%
@@ -675,6 +669,7 @@
%% Compatibility with array package
+\ExplSyntaxOn
\def\ltj@lltjext@patch@array{%
\patchcmd{\@tabular}{\hbox\bgroup}{%
\hbox\bgroup\ltj@ext@dir=\ltjgetparameter{direction}\relax}{}{}
@@ -682,10 +677,6 @@
{\ltj@ext@dir=\ltjgetparameter{direction}\relax}{}{}
\expandafter\let\csname tabular*\endcsname=\ltj@lltjext@orig@tabularS
\patchcmd{\p@stabular}{\p@tabular}{\@tabular}{}{}
- \@ifpackagelater{array}{2018/09/13}
- {\expandafter\@firstoftwo}
- {\expandafter\@secondoftwo}
- {% = for 2018/09/13 v2.4i or newer
\def\@startpbox##1{\bgroup
\color@begingroup
\box@dir\adjustbaseline%%% これを追加
@@ -694,16 +685,8 @@
\vrule \@height \ltjgetht\@arstrutbox \@width \z@
\everypar{}}%
}%
- }{ % = for 2018/04/30 v2.4h or older
- \def\@startpbox##1{\bgroup
- \box@dir\adjustbaseline%%% これを追加
- \setlength\hsize{##1}\@arrayparboxrestore
- \everypar{%
- \vrule \@height \ltjgetht\@arstrutbox \@width \z@
- \everypar{}}%
- }%
- }%
\def\@tabarray{\@ifnextchar<\p@tabarray{\p@tabarray<Z>}}
+\ifcsname tbl_save_outer_table_cols:\endcsname %%%%%% >=2024-06-01
\def\p@array<##1>[##2]##3{%
\ifnum\ltj@ext@dir=0 \ltj@ext@dir=\ltjgetparameter{direction}\relax\fi
\let\box@dir\relax
@@ -736,20 +719,98 @@
\@depth \arraystretch \ltjgetdp \@tempcnta
\@width \z@}%
\fork@array@option<##1>[##2]%
+ \tbl_save_outer_table_cols:
\begingroup
\@mkpream{##3}%
- \xdef\@preamble{\noexpand\ialign \noexpand \@halignto
- \bgroup \tabskip \z@skip \@arstrut \@preamble
- \tabskip \z@ \cr}%
+ \tbl_count_table_cols:
+ \xdef\@preamble{
+ \noexpand\ar@ialign
+ \@halignto
+ \bgroup \@arstrut
+ \UseTaggingSocket{tbl/row/begin}
+ \tbl_init_cell_data_for_row:
+ \@preamble
+ \tabskip \z@ \cr}%
\endgroup
\@arrayleft
- \@begin@alignbox\bgroup\box@dir\adjustbaseline
- \let\par\@empty
- \let\@sharp####\let\protect\relax
- \let\\\@arraycr\let\tabularnewline\\\let\par\@empty
- \lineskip\z@skip\baselineskip\z@skip\@preamble}
- \def\endarray{\crcr\egroup\egroup\@end@alignbox\@arrayright}
+ \@begin@alignbox
+ \bgroup
+ \box@dir\adjustbaseline
+ \let\@sharp####\let\protect\relax
+ \lineskip \z@
+ \baselineskip \z@
+ \mathsurround \z@
+ \let\\\@arraycr \let\tabularnewline\\\let\par\@empty
+ \UseTaggingSocket{tbl/init}
+ \@preamble
+ }
+ \def\endtabular{\endarray$\egroup
+ \UseTaggingSocket {tbl/hmode/end}\null}
+ \def\endarray{
+ \tbl_crcr:n{endarray} \egroup
+ \UseTaggingSocket{tbl/finalize}
+ \tbl_restore_outer_cell_data:
+ \egroup\@end@alignbox
+ \@arrayright \gdef\@preamble{}%
+ }
+\else %%%%%% <2024-06-01
+ \def\p@array<##1>[##2]##3{%
+ \ifnum\ltj@ext@dir=0 \ltj@ext@dir=\ltjgetparameter{direction}\relax\fi
+ \let\box@dir\relax
+ \if ##1z\relax
+ \ifnum\ltj@ext@dir=3\relax
+ \let\box@dir\utod\@tempcnta=\zstrutbox
+ \fi
+ \else
+ \if ##1y\relax
+ \let\box@dir\yoko\@tempcnta=\ystrutbox
+ \else\if ##1t\relax
+ \let\box@dir\tate\@tempcnta=\tstrutbox
+ \else\if ##1d\relax
+ \let\box@dir\dtou\@tempcnta=\dstrutbox
+ \else\if ##1u\relax
+ \let\box@dir\utod\@tempcnta=\zstrutbox
+ \fi\fi\fi\fi
+ \fi
+ \ifx\box@dir\relax
+ \ifcase\ltj@ext@dir
+ \or \let\box@dir\dtou\@tempcnta=\dstrutbox% dtou
+ \or\or\let\box@dir\tate\@tempcnta=\tstrutbox% tate
+ \or \let\box@dir\yoko\@tempcnta=\ystrutbox% yoko
+ \else \let\box@dir\utod\@tempcnta=\zstrutbox% utod
+ \fi
+ \fi
+ \setbox \@arstrutbox \hbox{\box@dir\vrule
+ \@height \arraystretch
+ \dimexpr \ltjgetht\@tempcnta+\extrarowheight\relax
+ \@depth \arraystretch \ltjgetdp \@tempcnta
+ \@width \z@}%
+ \fork@array@option<##1>[##2]%
+ \begingroup
+ \@mkpream{##3}%
+ \xdef\@preamble{\noexpand\ialign \@halignto
+ \bgroup \@arstrut\@preamble \tabskip \z@ \cr}%
+ \endgroup
+ \@arrayleft
+ \@begin@alignbox
+ \bgroup
+ \box@dir\adjustbaseline
+ \let\@sharp####\let\protect\relax
+ \lineskip \z@
+ \baselineskip \z@
+ \m@th
+ \let\\\@arraycr \let\tabularnewline\\\let\par\@empty
+ \@preamble
+ }
+ \def\endtabular{\endarray\m@th$\egroup\null}
+ \def\endarray{
+ \crcr\egroup\egroup\@end@alignbox
+ \@arrayright \gdef\@preamble{}%
+ }
+\fi
+ \expandafter \let \csname endtabular*\endcsname = \endtabular
}
+\ExplSyntaxOff
\@ifpackageloaded{array}{%
\let\tabular=\ltj@lltjext@orig@tabular
\let\array=\ltj@lltjext@orig@array
@@ -760,9 +821,4 @@
\ltj@ExecuteAfterPackage{array}{\ltj@lltjext@patch@array}
}
-%%%%%%%%%%%%%%%% LuaTeX-ja original
-
-%%\define@key[ltj]{japaram}{autouprightnum}{% %COUNT
-%% \ltj@@set@stack{AURN}{0}{10000}\z@#1 }
-
\endinput
diff --git a/Master/texmf-dist/tex/luatex/luatexja/ltj-ivd_aj1.lua b/Master/texmf-dist/tex/luatex/luatexja/ltj-ivd_aj1.lua
index de18150d793..bb265c7e548 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/ltj-ivd_aj1.lua
+++ b/Master/texmf-dist/tex/luatex/luatexja/ltj-ivd_aj1.lua
@@ -6,6 +6,9 @@ table_ivd_aj1 = {
-- #
-- # History:
-- #
+-- # 2022-09-13 Registration of additional sequences in the Adobe-Japan1
+-- # collection.
+-- #
-- # 2020-11-06 Registration of additional sequences in the MSARG
-- # collection.
-- #
@@ -36,7 +39,7 @@ table_ivd_aj1 = {
-- # For more details on the IVD, see UTS #37:
-- # https://www.unicode.org/reports/tr37/
-- #
--- # Copyright 2006-2020 Unicode, Inc.
+-- # Copyright 2006-2022 Unicode, Inc.
-- # For terms of use, see: https://www.unicode.org/copyright.html#8
-- #
-- # EOF
@@ -1952,7 +1955,7 @@ table_ivd_aj1 = {
0x209dbf,0x209db5,0x209db9,0x209dbd,0x209dc9,0x209dda,0x209de0,0x209de3,0x204d07,0x209e0a,
0x209e02,0x209e0d,0x209e1c,0x209e7b,0x222218,0x209e80,0x209e85,0x209e9b,0x22a38c,0x209ebd,
0x22a437,0x209edf,0x209eff,0x209f02,0x204d77,0x209f03,0x209f3a,0x209f3d,0x209f46,0x209f53,
- 0x209f55,0x209f58,0x22a5f1,0x209f5d,0x22a602,0x209f69,0x209f6d,0x209f70,0x22a6b2,0x20793a,
+ 0x209f55,0x209f58,0x22a5f1,0x209f5d,0x22a602,0x209f69,0x209f6d,0x209f70,0x22a6b2,0x231350,
0x203614,0x2038ad,0x203dcc,0x203fdc,0x2045be,0x204610,0x204b7e,0x204c38,0x204ce1,0x204e0c,
0x204e23,0x204e24,0x204e79,0x204ef3,0x204f0c,0x204f19,0x204f2b,0x204f2e,0x204f31,0x204f84,
0x204f9e,0x204fb7,0x205004,0x20500c,0x20504c,0x20505f,0x205062,0x205077,0x20508e,0x20509e,
diff --git a/Master/texmf-dist/tex/luatex/luatexja/ltj-jfmglue.lua b/Master/texmf-dist/tex/luatex/luatexja/ltj-jfmglue.lua
index ed7ab6daa8a..6eda9f0fdeb 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/ltj-jfmglue.lua
+++ b/Master/texmf-dist/tex/luatex/luatexja/ltj-jfmglue.lua
@@ -3,7 +3,7 @@
--
luatexbase.provides_module({
name = 'luatexja.jfmglue',
- date = '2022-08-29',
+ date = '2024-09-01',
description = 'Insertion process of JFM glues, [x]kanjiskip and others',
})
luatexja.jfmglue = luatexja.jfmglue or {}
@@ -741,7 +741,7 @@ local function handle_penalty_jwp()
local a = table_current_stack[luatexja.stack_table_index.JWP]
if #widow_Bp == 0 then
if a~=0 then
- local p = node_new(id_penalty, widow_Np.nuc)
+ local p = node_new(id_penalty, nil, widow_Np.nuc)
if a<-10000 then a = -10000 elseif a>10000 then a = 10000 end
setpenalty(p, a); head = insert_before(head, widow_Np.first, p)
widow_Bp[1]=p; set_attr(p, attr_icflag, KINSOKU)
@@ -1059,7 +1059,7 @@ local function handle_np_jachar(mode)
real_insert(g)
end
if mode and Np.kcat%2~=1 then
- widow_Np.first, widow_Bp, Bp = Np.first, Bp, widow_Bp
+ widow_Np.nuc, widow_Np.first, widow_Bp, Bp = Np.nuc, Np.first, Bp, widow_Bp
end
end
diff --git a/Master/texmf-dist/tex/luatex/luatexja/ltj-jfont.lua b/Master/texmf-dist/tex/luatex/luatexja/ltj-jfont.lua
index 26c76d88a13..3e685c0b41f 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/ltj-jfont.lua
+++ b/Master/texmf-dist/tex/luatex/luatexja/ltj-jfont.lua
@@ -3,7 +3,7 @@
--
luatexbase.provides_module({
name = 'luatexja.jfont',
- date = '2023-04-06',
+ date = '2024-07-25',
description = 'Loader for Japanese fonts',
})
@@ -434,17 +434,18 @@ do
end
-- extract jfm_name, jfm_spec and jfm_var
-- normalize position of 'jfm=' and 'jfmvar=' keys
+ local match, sub = string.match, string.sub
local function extract_jfm_spec(name)
- name = (name:match '^{(.*)}$') or (name:match '^"(.*)"$') or name
+ name = (match(name,'^{(.*)}$')) or (match(name,'^"(.*)"$')) or name
jfm_spec, jfm_var = '', ''
- local tmp, index = name:sub(1, 5), 1
+ local tmp, index = sub(name,1, 5), 1
if tmp == 'file:' or tmp == 'name:' or tmp == 'psft:' then
index = 6
end
name = lpegmatch(jf_remainder, name)
if jfm_name~='' then
if luatexja.jfont.jfm_feature then
- local l, t2 = name:sub(-1), {}
+ local l, t2 = sub(name,-1), {}
for i,v in pairs(luatexja.jfont.jfm_feature) do
-- print(i,type(v),v)
t2[#t2+1] = (v==true) and i
@@ -454,7 +455,7 @@ do
else
jfm_spec = jfm_name
end
- l = name:sub(-1)
+ l = sub(name,-1)
name = name .. ((l==':' or l==';') and '' or ';') .. 'jfm=' .. jfm_spec
if jfm_var~='' then
name = name .. ';jfmvar=' .. jfm_var
@@ -806,9 +807,9 @@ local list_rotate_glyphs
do
local ceil = math.ceil
-- output of function_uax50.lua
- -- UAX#50 for Unicode 14.0.0
+ -- UAX#50 for Unicode 15.1.0
-- t[0] = true
- local t={ 0, 167, 168, 169, 170, 174, 175, 177, 178, 188, 191, 215, 216, 247, 248, 746, 748, 888, 890, 896, 900, 907, 908, 909, 910, 930, 931, 1328, 1329, 1367, 1369, 1419, 1421, 1424, 1425, 1480, 1488, 1515, 1519, 1525, 1536, 1806, 1807, 1867, 1869, 1970, 1984, 2043, 2045, 2094, 2096, 2111, 2112, 2140, 2142, 2143, 2144, 2155, 2160, 2191, 2192, 2194, 2200, 2436, 2437, 2445, 2447, 2449, 2451, 2473, 2474, 2481, 2482, 2483, 2486, 2490, 2492, 2501, 2503, 2505, 2507, 2511, 2519, 2520, 2524, 2526, 2527, 2532, 2534, 2559, 2561, 2564, 2565, 2571, 2575, 2577, 2579, 2601, 2602, 2609, 2610, 2612, 2613, 2615, 2616, 2618, 2620, 2621, 2622, 2627, 2631, 2633, 2635, 2638, 2641, 2642, 2649, 2653, 2654, 2655, 2662, 2679, 2689, 2692, 2693, 2702, 2703, 2706, 2707, 2729, 2730, 2737, 2738, 2740, 2741, 2746, 2748, 2758, 2759, 2762, 2763, 2766, 2768, 2769, 2784, 2788, 2790, 2802, 2809, 2816, 2817, 2820, 2821, 2829, 2831, 2833, 2835, 2857, 2858, 2865, 2866, 2868, 2869, 2874, 2876, 2885, 2887, 2889, 2891, 2894, 2901, 2904, 2908, 2910, 2911, 2916, 2918, 2936, 2946, 2948, 2949, 2955, 2958, 2961, 2962, 2966, 2969, 2971, 2972, 2973, 2974, 2976, 2979, 2981, 2984, 2987, 2990, 3002, 3006, 3011, 3014, 3017, 3018, 3022, 3024, 3025, 3031, 3032, 3046, 3067, 3072, 3085, 3086, 3089, 3090, 3113, 3114, 3130, 3132, 3141, 3142, 3145, 3146, 3150, 3157, 3159, 3160, 3163, 3165, 3166, 3168, 3172, 3174, 3184, 3191, 3213, 3214, 3217, 3218, 3241, 3242, 3252, 3253, 3258, 3260, 3269, 3270, 3273, 3274, 3278, 3285, 3287, 3293, 3295, 3296, 3300, 3302, 3312, 3313, 3315, 3328, 3341, 3342, 3345, 3346, 3397, 3398, 3401, 3402, 3408, 3412, 3428, 3430, 3456, 3457, 3460, 3461, 3479, 3482, 3506, 3507, 3516, 3517, 3518, 3520, 3527, 3530, 3531, 3535, 3541, 3542, 3543, 3544, 3552, 3558, 3568, 3570, 3573, 3585, 3643, 3647, 3676, 3713, 3715, 3716, 3717, 3718, 3723, 3724, 3748, 3749, 3750, 3751, 3774, 3776, 3781, 3782, 3783, 3784, 3790, 3792, 3802, 3804, 3808, 3840, 3912, 3913, 3949, 3953, 3992, 3993, 4029, 4030, 4045, 4046, 4059, 4096, 4294, 4295, 4296, 4301, 4302, 4304, 4352, 4608, 4681, 4682, 4686, 4688, 4695, 4696, 4697, 4698, 4702, 4704, 4745, 4746, 4750, 4752, 4785, 4786, 4790, 4792, 4799, 4800, 4801, 4802, 4806, 4808, 4823, 4824, 4881, 4882, 4886, 4888, 4955, 4957, 4989, 4992, 5018, 5024, 5110, 5112, 5118, 5120, 5121, 5760, 5789, 5792, 5881, 5888, 5910, 5919, 5943, 5952, 5972, 5984, 5997, 5998, 6001, 6002, 6004, 6016, 6110, 6112, 6122, 6128, 6138, 6144, 6170, 6176, 6265, 6272, 6315, 6400, 6431, 6432, 6444, 6448, 6460, 6464, 6465, 6468, 6510, 6512, 6517, 6528, 6572, 6576, 6602, 6608, 6619, 6622, 6684, 6686, 6751, 6752, 6781, 6783, 6794, 6800, 6810, 6816, 6830, 6832, 6863, 6912, 6989, 6992, 7039, 7040, 7156, 7164, 7224, 7227, 7242, 7245, 7305, 7312, 7355, 7357, 7368, 7376, 7419, 7424, 7958, 7960, 7966, 7968, 8006, 8008, 8014, 8016, 8024, 8025, 8026, 8027, 8028, 8029, 8030, 8031, 8062, 8064, 8117, 8118, 8133, 8134, 8148, 8150, 8156, 8157, 8176, 8178, 8181, 8182, 8191, 8192, 8214, 8215, 8224, 8226, 8240, 8242, 8251, 8253, 8258, 8259, 8263, 8266, 8273, 8274, 8293, 8294, 8306, 8308, 8335, 8336, 8349, 8352, 8385, 8400, 8413, 8417, 8418, 8421, 8433, 8450, 8451, 8458, 8463, 8464, 8467, 8469, 8470, 8472, 8478, 8484, 8485, 8486, 8487, 8488, 8489, 8490, 8494, 8495, 8501, 8512, 8517, 8523, 8524, 8526, 8527, 8586, 8588, 8592, 8734, 8735, 8756, 8758, 8960, 8968, 8972, 8992, 8996, 9001, 9003, 9004, 9085, 9115, 9150, 9166, 9167, 9168, 9169, 9180, 9186, 9251, 9252, 9472, 9632, 9754, 9760, 10088, 10102, 10132, 11026, 11056, 11088, 11098, 11124, 11126, 11158, 11160, 11192, 11218, 11219, 11244, 11248, 11264, 11508, 11513, 11558, 11559, 11560, 11565, 11566, 11568, 11624, 11631, 11633, 11647, 11671, 11680, 11687, 11688, 11695, 11696, 11703, 11704, 11711, 11712, 11719, 11720, 11727, 11728, 11735, 11736, 11743, 11744, 11856, 11858, 11870, 12296, 12306, 12308, 12320, 12336, 12337, 12448, 12449, 12540, 12541, 42192, 42540, 42560, 42744, 42752, 42955, 42960, 42962, 42963, 42964, 42965, 42970, 42994, 43053, 43056, 43066, 43072, 43128, 43136, 43206, 43214, 43226, 43232, 43348, 43359, 43360, 43392, 43470, 43471, 43482, 43486, 43519, 43520, 43575, 43584, 43598, 43600, 43610, 43612, 43715, 43739, 43767, 43777, 43783, 43785, 43791, 43793, 43799, 43808, 43815, 43816, 43823, 43824, 43884, 43888, 44014, 44016, 44026, 55296, 57344, 64256, 64263, 64275, 64280, 64285, 64311, 64312, 64317, 64318, 64319, 64320, 64322, 64323, 64325, 64326, 64451, 64467, 64912, 64914, 64968, 64975, 64976, 65008, 65040, 65056, 65072, 65097, 65104, 65112, 65119, 65123, 65127, 65136, 65141, 65142, 65277, 65279, 65280, 65288, 65290, 65293, 65294, 65306, 65311, 65339, 65340, 65341, 65342, 65343, 65344, 65371, 65471, 65474, 65480, 65482, 65488, 65490, 65496, 65498, 65501, 65507, 65508, 65512, 65519, 65529, 65532, 65536, 65548, 65549, 65575, 65576, 65595, 65596, 65598, 65599, 65614, 65616, 65630, 65664, 65787, 65792, 65795, 65799, 65844, 65847, 65935, 65936, 65949, 65952, 65953, 66000, 66046, 66176, 66205, 66208, 66257, 66272, 66300, 66304, 66340, 66349, 66379, 66384, 66427, 66432, 66462, 66463, 66500, 66504, 66518, 66560, 66718, 66720, 66730, 66736, 66772, 66776, 66812, 66816, 66856, 66864, 66916, 66927, 66939, 66940, 66955, 66956, 66963, 66964, 66966, 66967, 66978, 66979, 66994, 66995, 67002, 67003, 67005, 67072, 67383, 67392, 67414, 67424, 67432, 67456, 67462, 67463, 67505, 67506, 67515, 67584, 67590, 67592, 67593, 67594, 67638, 67639, 67641, 67644, 67645, 67647, 67670, 67671, 67743, 67751, 67760, 67808, 67827, 67828, 67830, 67835, 67868, 67871, 67898, 67903, 67904, 68000, 68024, 68028, 68048, 68050, 68100, 68101, 68103, 68108, 68116, 68117, 68120, 68121, 68150, 68152, 68155, 68159, 68169, 68176, 68185, 68192, 68256, 68288, 68327, 68331, 68343, 68352, 68406, 68409, 68438, 68440, 68467, 68472, 68498, 68505, 68509, 68521, 68528, 68608, 68681, 68736, 68787, 68800, 68851, 68858, 68904, 68912, 68922, 69216, 69247, 69248, 69290, 69291, 69294, 69296, 69298, 69376, 69416, 69424, 69466, 69488, 69514, 69552, 69580, 69600, 69623, 69632, 69710, 69714, 69750, 69759, 69827, 69837, 69838, 69840, 69865, 69872, 69882, 69888, 69941, 69942, 69960, 69968, 70007, 70016, 70112, 70113, 70133, 70144, 70162, 70163, 70207, 70272, 70279, 70280, 70281, 70282, 70286, 70287, 70302, 70303, 70314, 70320, 70379, 70384, 70394, 70400, 70404, 70405, 70413, 70415, 70417, 70419, 70441, 70442, 70449, 70450, 70452, 70453, 70458, 70459, 70469, 70471, 70473, 70475, 70478, 70480, 70481, 70487, 70488, 70493, 70500, 70502, 70509, 70512, 70517, 70656, 70748, 70749, 70754, 70784, 70856, 70864, 70874, 71168, 71237, 71248, 71258, 71264, 71277, 71296, 71354, 71360, 71370, 71424, 71451, 71453, 71468, 71472, 71495, 71680, 71740, 71840, 71923, 71935, 71943, 71945, 71946, 71948, 71956, 71957, 71959, 71960, 71990, 71991, 71993, 71995, 72007, 72016, 72026, 72096, 72104, 72106, 72152, 72154, 72165, 72384, 72441, 72704, 72713, 72714, 72759, 72760, 72774, 72784, 72813, 72816, 72848, 72850, 72872, 72873, 72887, 72960, 72967, 72968, 72970, 72971, 73015, 73018, 73019, 73020, 73022, 73023, 73032, 73040, 73050, 73056, 73062, 73063, 73065, 73066, 73103, 73104, 73106, 73107, 73113, 73120, 73130, 73440, 73465, 73648, 73649, 73664, 73714, 73727, 74650, 74752, 74863, 74864, 74869, 74880, 75076, 77712, 77811, 92160, 92729, 92736, 92767, 92768, 92778, 92782, 92863, 92864, 92874, 92880, 92910, 92912, 92918, 92928, 92998, 93008, 93018, 93019, 93026, 93027, 93048, 93053, 93072, 93760, 93851, 93952, 94027, 94031, 94088, 94095, 94112, 113664, 113771, 113776, 113789, 113792, 113801, 113808, 113818, 113820, 113828, 119296, 119366, 119808, 119893, 119894, 119965, 119966, 119968, 119970, 119971, 119973, 119975, 119977, 119981, 119982, 119994, 119995, 119996, 119997, 120004, 120005, 120070, 120071, 120075, 120077, 120085, 120086, 120093, 120094, 120122, 120123, 120127, 120128, 120133, 120134, 120135, 120138, 120145, 120146, 120486, 120488, 120780, 120782, 120832, 122624, 122655, 122880, 122887, 122888, 122905, 122907, 122914, 122915, 122917, 122918, 122923, 123136, 123181, 123184, 123198, 123200, 123210, 123214, 123216, 123536, 123567, 123584, 123642, 123647, 123648, 124896, 124903, 124904, 124908, 124909, 124911, 124912, 124927, 124928, 125125, 125127, 125143, 125184, 125260, 125264, 125274, 125278, 125280, 126065, 126133, 126209, 126270, 126464, 126468, 126469, 126496, 126497, 126499, 126500, 126501, 126503, 126504, 126505, 126515, 126516, 126520, 126521, 126522, 126523, 126524, 126530, 126531, 126535, 126536, 126537, 126538, 126539, 126540, 126541, 126544, 126545, 126547, 126548, 126549, 126551, 126552, 126553, 126554, 126555, 126556, 126557, 126558, 126559, 126560, 126561, 126563, 126564, 126565, 126567, 126571, 126572, 126579, 126580, 126584, 126585, 126589, 126590, 126591, 126592, 126602, 126603, 126620, 126625, 126628, 126629, 126634, 126635, 126652, 126704, 126706, 129024, 129036, 129040, 129096, 129104, 129114, 129120, 129160, 129168, 129198, 129200, 129202, 129792, 129939, 129940, 129995, 130032, 130042, 917505, 917506, 917536, 917632, 917760, 918000 }
+ local t={ 0, 167, 168, 169, 170, 174, 175, 177, 178, 188, 191, 215, 216, 247, 248, 746, 748, 888, 890, 896, 900, 907, 908, 909, 910, 930, 931, 1328, 1329, 1367, 1369, 1419, 1421, 1424, 1425, 1480, 1488, 1515, 1519, 1525, 1536, 1806, 1807, 1867, 1869, 1970, 1984, 2043, 2045, 2094, 2096, 2111, 2112, 2140, 2142, 2143, 2144, 2155, 2160, 2191, 2192, 2194, 2200, 2436, 2437, 2445, 2447, 2449, 2451, 2473, 2474, 2481, 2482, 2483, 2486, 2490, 2492, 2501, 2503, 2505, 2507, 2511, 2519, 2520, 2524, 2526, 2527, 2532, 2534, 2559, 2561, 2564, 2565, 2571, 2575, 2577, 2579, 2601, 2602, 2609, 2610, 2612, 2613, 2615, 2616, 2618, 2620, 2621, 2622, 2627, 2631, 2633, 2635, 2638, 2641, 2642, 2649, 2653, 2654, 2655, 2662, 2679, 2689, 2692, 2693, 2702, 2703, 2706, 2707, 2729, 2730, 2737, 2738, 2740, 2741, 2746, 2748, 2758, 2759, 2762, 2763, 2766, 2768, 2769, 2784, 2788, 2790, 2802, 2809, 2816, 2817, 2820, 2821, 2829, 2831, 2833, 2835, 2857, 2858, 2865, 2866, 2868, 2869, 2874, 2876, 2885, 2887, 2889, 2891, 2894, 2901, 2904, 2908, 2910, 2911, 2916, 2918, 2936, 2946, 2948, 2949, 2955, 2958, 2961, 2962, 2966, 2969, 2971, 2972, 2973, 2974, 2976, 2979, 2981, 2984, 2987, 2990, 3002, 3006, 3011, 3014, 3017, 3018, 3022, 3024, 3025, 3031, 3032, 3046, 3067, 3072, 3085, 3086, 3089, 3090, 3113, 3114, 3130, 3132, 3141, 3142, 3145, 3146, 3150, 3157, 3159, 3160, 3163, 3165, 3166, 3168, 3172, 3174, 3184, 3191, 3213, 3214, 3217, 3218, 3241, 3242, 3252, 3253, 3258, 3260, 3269, 3270, 3273, 3274, 3278, 3285, 3287, 3293, 3295, 3296, 3300, 3302, 3312, 3313, 3316, 3328, 3341, 3342, 3345, 3346, 3397, 3398, 3401, 3402, 3408, 3412, 3428, 3430, 3456, 3457, 3460, 3461, 3479, 3482, 3506, 3507, 3516, 3517, 3518, 3520, 3527, 3530, 3531, 3535, 3541, 3542, 3543, 3544, 3552, 3558, 3568, 3570, 3573, 3585, 3643, 3647, 3676, 3713, 3715, 3716, 3717, 3718, 3723, 3724, 3748, 3749, 3750, 3751, 3774, 3776, 3781, 3782, 3783, 3784, 3791, 3792, 3802, 3804, 3808, 3840, 3912, 3913, 3949, 3953, 3992, 3993, 4029, 4030, 4045, 4046, 4059, 4096, 4294, 4295, 4296, 4301, 4302, 4304, 4352, 4608, 4681, 4682, 4686, 4688, 4695, 4696, 4697, 4698, 4702, 4704, 4745, 4746, 4750, 4752, 4785, 4786, 4790, 4792, 4799, 4800, 4801, 4802, 4806, 4808, 4823, 4824, 4881, 4882, 4886, 4888, 4955, 4957, 4989, 4992, 5018, 5024, 5110, 5112, 5118, 5120, 5121, 5760, 5789, 5792, 5881, 5888, 5910, 5919, 5943, 5952, 5972, 5984, 5997, 5998, 6001, 6002, 6004, 6016, 6110, 6112, 6122, 6128, 6138, 6144, 6170, 6176, 6265, 6272, 6315, 6400, 6431, 6432, 6444, 6448, 6460, 6464, 6465, 6468, 6510, 6512, 6517, 6528, 6572, 6576, 6602, 6608, 6619, 6622, 6684, 6686, 6751, 6752, 6781, 6783, 6794, 6800, 6810, 6816, 6830, 6832, 6863, 6912, 6989, 6992, 7039, 7040, 7156, 7164, 7224, 7227, 7242, 7245, 7305, 7312, 7355, 7357, 7368, 7376, 7419, 7424, 7958, 7960, 7966, 7968, 8006, 8008, 8014, 8016, 8024, 8025, 8026, 8027, 8028, 8029, 8030, 8031, 8062, 8064, 8117, 8118, 8133, 8134, 8148, 8150, 8156, 8157, 8176, 8178, 8181, 8182, 8191, 8192, 8214, 8215, 8224, 8226, 8240, 8242, 8251, 8253, 8258, 8259, 8263, 8266, 8273, 8274, 8293, 8294, 8306, 8308, 8335, 8336, 8349, 8352, 8385, 8400, 8413, 8417, 8418, 8421, 8433, 8450, 8451, 8458, 8463, 8464, 8467, 8469, 8470, 8472, 8478, 8484, 8485, 8486, 8487, 8488, 8489, 8490, 8494, 8495, 8501, 8512, 8517, 8523, 8524, 8526, 8527, 8586, 8588, 8592, 8734, 8735, 8756, 8758, 8960, 8968, 8972, 8992, 8996, 9001, 9003, 9004, 9085, 9115, 9150, 9166, 9167, 9168, 9169, 9180, 9186, 9251, 9252, 9472, 9632, 9754, 9760, 10088, 10102, 10132, 11026, 11056, 11088, 11098, 11124, 11126, 11158, 11160, 11192, 11218, 11219, 11244, 11248, 11264, 11508, 11513, 11558, 11559, 11560, 11565, 11566, 11568, 11624, 11631, 11633, 11647, 11671, 11680, 11687, 11688, 11695, 11696, 11703, 11704, 11711, 11712, 11719, 11720, 11727, 11728, 11735, 11736, 11743, 11744, 11856, 11858, 11870, 12296, 12306, 12308, 12320, 12336, 12337, 12448, 12449, 12540, 12541, 42192, 42540, 42560, 42744, 42752, 42955, 42960, 42962, 42963, 42964, 42965, 42970, 42994, 43053, 43056, 43066, 43072, 43128, 43136, 43206, 43214, 43226, 43232, 43348, 43359, 43360, 43392, 43470, 43471, 43482, 43486, 43519, 43520, 43575, 43584, 43598, 43600, 43610, 43612, 43715, 43739, 43767, 43777, 43783, 43785, 43791, 43793, 43799, 43808, 43815, 43816, 43823, 43824, 43884, 43888, 44014, 44016, 44026, 55296, 57344, 64256, 64263, 64275, 64280, 64285, 64311, 64312, 64317, 64318, 64319, 64320, 64322, 64323, 64325, 64326, 64451, 64467, 64912, 64914, 64968, 64975, 64976, 65008, 65040, 65056, 65072, 65097, 65104, 65112, 65119, 65123, 65127, 65136, 65141, 65142, 65277, 65279, 65280, 65288, 65290, 65293, 65294, 65306, 65311, 65339, 65340, 65341, 65342, 65343, 65344, 65371, 65471, 65474, 65480, 65482, 65488, 65490, 65496, 65498, 65501, 65507, 65508, 65512, 65519, 65529, 65532, 65536, 65548, 65549, 65575, 65576, 65595, 65596, 65598, 65599, 65614, 65616, 65630, 65664, 65787, 65792, 65795, 65799, 65844, 65847, 65935, 65936, 65949, 65952, 65953, 66000, 66046, 66176, 66205, 66208, 66257, 66272, 66300, 66304, 66340, 66349, 66379, 66384, 66427, 66432, 66462, 66463, 66500, 66504, 66518, 66560, 66718, 66720, 66730, 66736, 66772, 66776, 66812, 66816, 66856, 66864, 66916, 66927, 66939, 66940, 66955, 66956, 66963, 66964, 66966, 66967, 66978, 66979, 66994, 66995, 67002, 67003, 67005, 67072, 67383, 67392, 67414, 67424, 67432, 67456, 67462, 67463, 67505, 67506, 67515, 67584, 67590, 67592, 67593, 67594, 67638, 67639, 67641, 67644, 67645, 67647, 67670, 67671, 67743, 67751, 67760, 67808, 67827, 67828, 67830, 67835, 67868, 67871, 67898, 67903, 67904, 68000, 68024, 68028, 68048, 68050, 68100, 68101, 68103, 68108, 68116, 68117, 68120, 68121, 68150, 68152, 68155, 68159, 68169, 68176, 68185, 68192, 68256, 68288, 68327, 68331, 68343, 68352, 68406, 68409, 68438, 68440, 68467, 68472, 68498, 68505, 68509, 68521, 68528, 68608, 68681, 68736, 68787, 68800, 68851, 68858, 68904, 68912, 68922, 69216, 69247, 69248, 69290, 69291, 69294, 69296, 69298, 69373, 69416, 69424, 69466, 69488, 69514, 69552, 69580, 69600, 69623, 69632, 69710, 69714, 69750, 69759, 69827, 69837, 69838, 69840, 69865, 69872, 69882, 69888, 69941, 69942, 69960, 69968, 70007, 70016, 70112, 70113, 70133, 70144, 70162, 70163, 70210, 70272, 70279, 70280, 70281, 70282, 70286, 70287, 70302, 70303, 70314, 70320, 70379, 70384, 70394, 70400, 70404, 70405, 70413, 70415, 70417, 70419, 70441, 70442, 70449, 70450, 70452, 70453, 70458, 70459, 70469, 70471, 70473, 70475, 70478, 70480, 70481, 70487, 70488, 70493, 70500, 70502, 70509, 70512, 70517, 70656, 70748, 70749, 70754, 70784, 70856, 70864, 70874, 71168, 71237, 71248, 71258, 71264, 71277, 71296, 71354, 71360, 71370, 71424, 71451, 71453, 71468, 71472, 71495, 71680, 71740, 71840, 71923, 71935, 71943, 71945, 71946, 71948, 71956, 71957, 71959, 71960, 71990, 71991, 71993, 71995, 72007, 72016, 72026, 72096, 72104, 72106, 72152, 72154, 72165, 72384, 72441, 72448, 72458, 72704, 72713, 72714, 72759, 72760, 72774, 72784, 72813, 72816, 72848, 72850, 72872, 72873, 72887, 72960, 72967, 72968, 72970, 72971, 73015, 73018, 73019, 73020, 73022, 73023, 73032, 73040, 73050, 73056, 73062, 73063, 73065, 73066, 73103, 73104, 73106, 73107, 73113, 73120, 73130, 73440, 73465, 73472, 73489, 73490, 73531, 73534, 73562, 73648, 73649, 73664, 73714, 73727, 74650, 74752, 74863, 74864, 74869, 74880, 75076, 77712, 77811, 92160, 92729, 92736, 92767, 92768, 92778, 92782, 92863, 92864, 92874, 92880, 92910, 92912, 92918, 92928, 92998, 93008, 93018, 93019, 93026, 93027, 93048, 93053, 93072, 93760, 93851, 93952, 94027, 94031, 94088, 94095, 94112, 113664, 113771, 113776, 113789, 113792, 113801, 113808, 113818, 113820, 113828, 119296, 119366, 119488, 119508, 119808, 119893, 119894, 119965, 119966, 119968, 119970, 119971, 119973, 119975, 119977, 119981, 119982, 119994, 119995, 119996, 119997, 120004, 120005, 120070, 120071, 120075, 120077, 120085, 120086, 120093, 120094, 120122, 120123, 120127, 120128, 120133, 120134, 120135, 120138, 120145, 120146, 120486, 120488, 120780, 120782, 120832, 122624, 122655, 122661, 122667, 122880, 122887, 122888, 122905, 122907, 122914, 122915, 122917, 122918, 122923, 122928, 122990, 123023, 123024, 123136, 123181, 123184, 123198, 123200, 123210, 123214, 123216, 123536, 123567, 123584, 123642, 123647, 123648, 124112, 124154, 124896, 124903, 124904, 124908, 124909, 124911, 124912, 124927, 124928, 125125, 125127, 125143, 125184, 125260, 125264, 125274, 125278, 125280, 126065, 126133, 126209, 126270, 126464, 126468, 126469, 126496, 126497, 126499, 126500, 126501, 126503, 126504, 126505, 126515, 126516, 126520, 126521, 126522, 126523, 126524, 126530, 126531, 126535, 126536, 126537, 126538, 126539, 126540, 126541, 126544, 126545, 126547, 126548, 126549, 126551, 126552, 126553, 126554, 126555, 126556, 126557, 126558, 126559, 126560, 126561, 126563, 126564, 126565, 126567, 126571, 126572, 126579, 126580, 126584, 126585, 126589, 126590, 126591, 126592, 126602, 126603, 126620, 126625, 126628, 126629, 126634, 126635, 126652, 126704, 126706, 129024, 129036, 129040, 129096, 129104, 129114, 129120, 129160, 129168, 129198, 129200, 129202, 129792, 129939, 129940, 129995, 130032, 130042, 917505, 917506, 917536, 917632, 917760, 918000 }
local function rotate_in_uax50(i)
local lo, hi = 1, #t
while lo < hi do
@@ -902,9 +903,10 @@ do
end
end
+ local sub = string.sub
local function prepare_extra_data_font(id, res, name)
if type(res)=='table' and (res.psname or res.filename) then
- if (res.embedding=='no') and (type(name)=='string') and (name:sub(1,5)=='psft:') then
+ if (res.embedding=='no') and (type(name)=='string') and (sub(name,1,5)=='psft:') then
font_extra_info[id] = res.resources.ltj_extra
else
local bname = res.psname or nameonly(res.filename)
diff --git a/Master/texmf-dist/tex/luatex/luatexja/ltj-latex.sty b/Master/texmf-dist/tex/luatex/luatexja/ltj-latex.sty
index 7e091d161d1..9f6e4d0a365 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/ltj-latex.sty
+++ b/Master/texmf-dist/tex/luatex/luatexja/ltj-latex.sty
@@ -12,45 +12,14 @@
\def\luatexjalatexLoaded{\endinput}
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{ltj-latex}[2022-10-15 LaTeX support of LuaTeX-ja]
+\ProvidesPackage{ltj-latex}[2024-05-16 LaTeX support of LuaTeX-ja]
\endlinechar=13
%%% LaTeX version detection
-\newif\ifltj@ltfilehook@avail
-\@ifl@t@r\fmtversion{2020-10-01}{%
- \@ifl@t@r\fmtversion{2020-10-02}%
- {\ltj@ltfilehook@availtrue}
- {%
- \ifnum\patch@level<0\relax \ifnum\patch@level<-6 \ltj@ltfilehook@availtrue\fi
- \else\ltj@ltfilehook@availtrue\fi
- }%
-}{}
-\@ifl@t@r\fmtversion{2021-05-01}{\count@=1 }{\count@=0 }
-\ifnum \count@<1
-%%%% \shipout
- \newluafunction\ltj@@lua@shipout@inner
- \directlua{
- local t = lua.get_functions_table()
- local getbox, setbox = tex.getbox, tex.setbox
- local shipout_lthook = luatexja.direction.shipout_lthook
- t[\the\ltj@@lua@shipout@inner]=function ()
- local a = shipout_lthook(getbox(\the\ltj@afbox))
- if a then setbox(\the\ltj@afbox, a) end
- end
- }
- \protected\luadef\ltj@@lua@shipout\ltj@@lua@shipout@inner
- \def\ltj@shipout@{\ltj@@lua@shipout\primitive\shipout\box\ltj@afbox}%
- \protected\def\ltj@shipout{\ltj@afterbox\ltj@shipout@}
- \ifprimitive\shipout\let\shipout\ltj@shipout\fi
- \ifcsname tex_shipout:D\endcsname
- \expandafter\let\csname tex_shipout:D\endcsname\ltj@shipout
- \fi
-\else
- \directlua{%
- luatexbase.add_to_callback('pre_shipout_filter',luatexja.direction.shipout_lthook, 'ltj.direction', 1)
- }
-\fi
+\directlua{%
+ luatexbase.add_to_callback('pre_shipout_filter',luatexja.direction.shipout_lthook, 'ltj.direction', 1)
+}
%%% patch for LaTeX
\usepackage{lltjfont}
@@ -59,36 +28,30 @@
\RequirePackage{lltjp-atbegshi}
%%% patching commands
-\ifltj@ltfilehook@avail
- %% \ltj@ExecuteBeforePackage <package><code> and \ltj@ExecuteAfterPackage <package><code>
- %% no-starred version: do nothing if the <package> is loaded
- %% starred version: do <code> right away if the <package> is loaded
- \def\ltj@ExecuteAfterPackage{\@ifstar\@@ltj@ExecuteAfterPackage@star\@@ltj@ExecuteAfterPackage}
- \def\ltj@ExecuteBeforePackage{\@ifstar\@@ltj@ExecuteBeforePackage@star\@@ltj@ExecuteBeforePackage}
- \@ifl@t@r\fmtversion{2021-11-15}{% 2021-11-15
- \def\@@ltj@ExecuteAfterPackage@star#1{\AddToHook{package/#1/after}}
- \def\@@ltj@ExecuteBeforePackage@star#1{\AddToHook{package/#1/before}}
- \long\def\@@ltj@ExecuteAfterPackage#1#2{%
- \@ifpackageloaded{#1}{}{\AddToHook{package/#1/after}{#2}}%
- }
- \long\def\@@ltj@ExecuteBeforePackage#1#2{%
- \@ifpackageloaded{#1}{}{\AddToHook{package/#1/before}{#2}}%
- }
- }{
- \def\@@ltj@ExecuteAfterPackage#1{\AddToHook{package/after/#1}}
- \def\@@ltj@ExecuteBeforePackage#1{\AddToHook{package/before/#1}}
- \long\def\@@ltj@ExecuteAfterPackage@star#1#2{%
- \@ifpackageloaded{#1}{#2}{\@@ltj@ExecuteAfterPackage{#1}{#2}}%
- }
- \long\def\@@ltj@ExecuteBeforePackage@star#1#2{%
- \@ifpackageloaded{#1}{#2}{\@@ltj@ExecuteBeforePackage{#1}{#2}}%
- }
+%% \ltj@ExecuteBeforePackage <package><code> and \ltj@ExecuteAfterPackage <package><code>
+%% no-starred version: do nothing if the <package> is loaded
+%% starred version: do <code> right away if the <package> is loaded
+\def\ltj@ExecuteAfterPackage{\@ifstar\@@ltj@ExecuteAfterPackage@star\@@ltj@ExecuteAfterPackage}
+\def\ltj@ExecuteBeforePackage{\@ifstar\@@ltj@ExecuteBeforePackage@star\@@ltj@ExecuteBeforePackage}
+\@ifl@t@r\fmtversion{2021-11-15}{% 2021-11-15
+ \def\@@ltj@ExecuteAfterPackage@star#1{\AddToHook{package/#1/after}}
+ \def\@@ltj@ExecuteBeforePackage@star#1{\AddToHook{package/#1/before}}
+ \long\def\@@ltj@ExecuteAfterPackage#1#2{%
+ \@ifpackageloaded{#1}{}{\AddToHook{package/#1/after}{#2}}%
}
-\else
- \RequirePackage{filehook}
- \let\ltj@ExecuteAfterPackage=\AtEndOfPackageFile
- \let\ltj@ExecuteBeforePackage=\AtBeginOfPackageFile
-\fi
+ \long\def\@@ltj@ExecuteBeforePackage#1#2{%
+ \@ifpackageloaded{#1}{}{\AddToHook{package/#1/before}{#2}}%
+ }
+}{
+ \def\@@ltj@ExecuteAfterPackage#1{\AddToHook{package/after/#1}}
+ \def\@@ltj@ExecuteBeforePackage#1{\AddToHook{package/before/#1}}
+ \long\def\@@ltj@ExecuteAfterPackage@star#1#2{%
+ \@ifpackageloaded{#1}{#2}{\@@ltj@ExecuteAfterPackage{#1}{#2}}%
+ }
+ \long\def\@@ltj@ExecuteBeforePackage@star#1#2{%
+ \@ifpackageloaded{#1}{#2}{\@@ltj@ExecuteBeforePackage{#1}{#2}}%
+ }
+}
\def\ltj@pkgpatch@im#1{\@ifnextchar[{\ltj@pkgpatch@im@{#1}}{\ltj@pkgpatch@im@{#1}[lltjp-#1]}}%]
\def\ltj@pkgpatch@im@#1[#2]{\ltj@ExecuteAfterPackage*{#1}{\ltj@pkgpatch@im@@{#2}}}
\def\ltj@pkgpatch@im@@#1{%
@@ -101,11 +64,7 @@
}
\def\ltj@pkgpatch#1{\@ifnextchar[{\ltj@pkgpatch@{#1}}{\ltj@pkgpatch@{#1}[lltjp-#1]}}%]
-\ifltj@ltfilehook@avail
- \def\ltj@pkgpatch@@{\AddToHook{begindocument/before}[luatexja.autopatch]}
-\else
- \def\ltj@pkgpatch@@{\gpreto\@begindocumenthook}
-\fi
+\def\ltj@pkgpatch@@{\AddToHook{begindocument/before}[luatexja.autopatch]}
\def\ltj@pkgpatch@#1[#2]{%
\ltj@pkgpatch@@{%
\@ifpackageloaded{#1}{\@ifpackageloaded{#2}{}{\RequirePackage{#2}}}{}%
@@ -121,18 +80,12 @@
\ltj@pkgpatch{tascmac}
\ltj@pkgpatch{ascmac}[lltjp-tascmac]
\ltj@pkgpatch@im{stfloats}
-\ifltj@ltfilehook@avail\else
- \ltj@pkgpatch{preview} %% at \begin{document}
- % (preview package has delayed option)
-\fi
\ltj@pkgpatch{array} %% at \begin{document}
\ltj@pkgpatch{collcell} %% at \begin{document}
\ltj@pkgpatch@im{unicode-math}
\ltj@pkgpatch@im{siunitx}
\ltj@pkgpatch@im{microtype}
-\ifltj@ltfilehook@avail\else\ltj@pkgpatch@im{everyshi}\fi
-
\RequirePackage{lltjp-geometry}
\ltj@ExecuteBeforePackage{breqn}{%
diff --git a/Master/texmf-dist/tex/luatex/luatexja/ltj-pretreat.lua b/Master/texmf-dist/tex/luatex/luatexja/ltj-pretreat.lua
index 43ecac806c2..8f5632be4e3 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/ltj-pretreat.lua
+++ b/Master/texmf-dist/tex/luatex/luatexja/ltj-pretreat.lua
@@ -156,16 +156,17 @@ function set_box_stack_level(head, mode)
if ltjs.list_dir == dir_tate then
for p in traverse_glyph(to_direct(head)) do
if getlang(p)==lang_ja and has_attr(p, attr_icflag, 0) then
- local pf = ltjf_replace_altfont(attr_curtfnt, getchar(p), p)
+ local pc = ltjs_orig_char_table[p] or getchar(p)
+ local pf = ltjf_replace_altfont(attr_curtfnt, pc, p)
if ltjf_font_metric_table[pf].vert_activated then
- local pc = ltjf_font_metric_table[pf].vform[pc]; if pc then setchar(p, pc) end
+ pc = ltjf_font_metric_table[pf].vform[pc]; if pc then setchar(p, pc) end
end
end
end
else
for p in traverse_glyph(to_direct(head)) do
if getlang(p)==lang_ja and has_attr(p, attr_icflag, 0) then
- ltjf_replace_altfont(attr_curjfnt, getchar(p), p)
+ ltjf_replace_altfont(attr_curjfnt, ltjs_orig_char_table[p] or getchar(p), p)
end
end
end
diff --git a/Master/texmf-dist/tex/luatex/luatexja/ltj-rmlgbm.lua b/Master/texmf-dist/tex/luatex/luatexja/ltj-rmlgbm.lua
index 88352dd5b24..23d20be3f36 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/ltj-rmlgbm.lua
+++ b/Master/texmf-dist/tex/luatex/luatexja/ltj-rmlgbm.lua
@@ -15,7 +15,8 @@ do
end
local cidfont_data = {}
local cache_chars = {}
-local cache_ver = 13
+local cache_ver = 14
+local sub = string.sub
local identifiers = fonts.hashes.identifiers
local cid_reg, cid_order, cid_supp, cid_name
@@ -147,7 +148,7 @@ do
descender = 655360*0.12,
},
embedding = "no", cache = "yes", factor = 0, hfactor = 0, vfactor = 0,
- tounicode = 1,
+ tounicode = 1, filename="",
properties = { language = "dflt", script = "dflt" },
}
cidfont_data[cid_name] = k
@@ -300,7 +301,6 @@ local function prepare_cid_font(reg, ord)
return cidfont_data[cid_name] or read_cid_font()
end
-
local definers = fonts.definers
local function mk_rml(name, size, id)
local specification = definers.analyze(name,size)
@@ -308,8 +308,8 @@ local function mk_rml(name, size, id)
specification.detail = specification.detail or ''
do
local n = specification.name
- if n:sub(1,1)=="{" then n=n:sub(2) end
- if n:sub(-1)=="}" then n=n:sub(1,-2) end
+ if sub(n,1,1)=="{" then n=sub(n,2) end
+ if sub(n,-1)=="}" then n=sub(n,1,-2) end
specification.name=n
end
local fontdata = {}
@@ -382,11 +382,11 @@ local function mk_rml(name, size, id)
end
local function font_callback(name, size, id, fallback)
- if name:sub(1,1)=="{" and name:sub(-1)=="}" then name = name:sub(2,-2) end
+ if sub(name,1,1)=="{" and sub(name,-1)=="}" then name = sub(name,2,-2) end
local p = name:find(":") or 0
- if name:sub(1, p-1) == 'psft' then
+ if sub(name,1, p-1) == 'psft' then
local s = "Adobe-Japan1-7"
- local basename = name:sub(p+1)
+ local basename = sub(name,p+1)
local p = basename:find(":")
local q = basename:find("/[BI][BI]?")
if q and p and q<=p then
@@ -394,12 +394,12 @@ local function font_callback(name, size, id, fallback)
p = basename:find(":")
end
if p then
- local xname = basename:sub(p+1)
+ local xname = sub(basename,p+1)
p = 1
while p do
local q = xname:find(";", p+1) or xname:len()+1
- if xname:sub(p, p+3)=='cid=' and q>p+4 then
- s = xname:sub(p+4, q-1)
+ if sub(xname,p, p+3)=='cid=' and q>p+4 then
+ s = sub(xname,p+4, q-1)
end
if xname:len()+1==q then p = nil else p = q + 1 end
end
diff --git a/Master/texmf-dist/tex/luatex/luatexja/ltj-ruby.lua b/Master/texmf-dist/tex/luatex/luatexja/ltj-ruby.lua
index 29b6fe19988..2ff41be9474 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/ltj-ruby.lua
+++ b/Master/texmf-dist/tex/luatex/luatexja/ltj-ruby.lua
@@ -3,7 +3,7 @@
--
luatexbase.provides_module({
name = 'luatexja.ruby',
- date = '2022-12-31',
+ date = '2024-09-06',
description = 'Ruby annotation',
})
luatexja.ruby = {}
@@ -37,7 +37,7 @@ local setwhd = node.direct.setwhd
local setlist = node.direct.setlist
local setvalue = node.direct.setdata
-local node_new = node.direct.new
+local node_new = luatexja.dnode_new
local node_remove = node.direct.remove
local node_next = node.direct.getnext
local node_copy, node_tail = node.direct.copy, node.direct.tail
@@ -45,6 +45,7 @@ local node_free = node.direct.flush_node or node.direct.free
local get_attr, set_attr = node.direct.get_attribute, node.direct.set_attribute
local insert_before, insert_after = node.direct.insert_before, node.direct.insert_after
local hpack = node.direct.hpack
+local node_inherit_attr = luatexja.node_inherit_attr
local id_hlist = node.id 'hlist'
local id_vlist = node.id 'vlist'
@@ -175,10 +176,10 @@ do
set_attr(nh, attr_icflag,
get_attr_icflag(nh) + PROCESSED_BEGIN_FLAG)
setnext(node_tail(h), nh)
- setlist(f, nil); node_free(f)
+ setlist(f, nil)
setlist(b, nil); node_free(b)
local g = luatexja.jfmglue.main(h,false)
- return hpack(g)
+ g = node_inherit_attr(hpack(g),f); node_free(f); return g
else
return f
end
@@ -207,6 +208,7 @@ end
-- box の中身のノードは再利用される
local enlarge
do
+ local dimensions = node.direct.dimensions
local FROM_JFM = luatexja.icflag_table.FROM_JFM
local PROCESSED = luatexja.icflag_table.PROCESSED
local KANJI_SKIP = luatexja.icflag_table.KANJI_SKIP
@@ -239,18 +241,22 @@ do
hx = node_next(hx)
end
-- 先頭の空白を挿入
- local k = node_new(id_glue);
- setglue(k, prenw, round(pre*65536), 0, 2, 0)
- h = insert_before(h, h, k);
+ local k1 = node_new(id_glue);
+ setglue(k1, prenw, round(pre*65536), 0, 2, 0)
+ h = insert_before(h, h, k1);
-- 末尾の空白を挿入
- local k = node_new(id_glue);
- setglue(k, postnw, round(post*65536), 0, 2, 0)
- insert_after(h, node_tail(h), k);
+ local k2 = node_new(id_glue);
+ setglue(k2, postnw, round(post*65536), 0, 2, 0)
+ insert_after(h, node_tail(h), k2);
-- hpack
- setlist(box, nil); node_free(box)
- box = hpack(h, new_width, 'exactly')
- setheight(box, hh); setdepth(box, hd)
- return box
+ setlist(box, nil);
+ local new_box = node_inherit_attr(hpack(h, new_width, 'exactly'), box)
+ setheight(new_box, hh); setdepth(new_box, hd)
+ node_free(box);
+ local gset, gsign, go
+ = getfield(new_box,'glue_set'), getfield(new_box,'glue_sign'), getfield(new_box,'glue_order')
+ return new_box, (dimensions(gset, gsign, go, k1, node_next(k1))), (dimensions(gset, gsign, go, k2))
+ -- return value: (enlarged box), (width of left glue), (width of right glue)
end
end
@@ -307,15 +313,18 @@ function luatexja.ruby.texiface(rst, rtlr, rtlp)
end
----------------------------------------------------------------
--- pre_line_break
+-- pre_linebreak
----------------------------------------------------------------
-- r, p の中身のノードは再利用される
local function enlarge_parent(r, p, tmp_tbl, no_begin, no_end)
-- r: ルビ部分の格納された box,p: 同,親文字
+ -- no_begin: 行頭形ではないか
+ -- no_end: 行末形ではないか
local rwidth = getwidth(r)
local sumprot = rwidth - getwidth(p) -- >0
local pre_intrusion, post_intrusion
+ local pre_protrusion, post_protrusion
local ppre, pmid, ppost = tmp_tbl.ppre, tmp_tbl.pmid, tmp_tbl.ppost
local mapre, mapost = tmp_tbl.mapre, tmp_tbl.mapost
local intmode = (tmp_tbl.mode//4)%8
@@ -325,17 +334,17 @@ local function enlarge_parent(r, p, tmp_tbl, no_begin, no_end)
mapre = min(mapre,mapost); mapost = mapre
end
if intmode == 0 then -- とりあえず組んでから決める
- p = enlarge(p, rwidth, ppre, pmid, ppost, 0, 0)
+ p, pre_protrusion, post_protrusion = enlarge(p, rwidth, ppre, pmid, ppost, 0, 0)
pre_intrusion = min(mapre, round(ppre*getfield(p, 'glue_set')*65536))
post_intrusion = min(mapost, round(ppost*getfield(p, 'glue_set')*65536))
elseif intmode == 1 then
pre_intrusion = min(mapre, sumprot);
post_intrusion = min(mapost, max(sumprot-pre_intrusion, 0))
- p = enlarge(p, rwidth, ppre, pmid, ppost, pre_intrusion, post_intrusion)
+ p, pre_protrusion, post_protrusion = enlarge(p, rwidth, ppre, pmid, ppost, pre_intrusion, post_intrusion)
elseif intmode == 2 then
post_intrusion = min(mapost, sumprot);
pre_intrusion = min(mapre, max(sumprot-post_intrusion, 0))
- p = enlarge(p, rwidth, ppre, pmid, ppost, pre_intrusion, post_intrusion)
+ p, pre_protrusion, post_protrusion = enlarge(p, rwidth, ppre, pmid, ppost, pre_intrusion, post_intrusion)
elseif intmode==3 then
local n = min(mapre, mapost)*2
if n < sumprot then
@@ -343,7 +352,7 @@ local function enlarge_parent(r, p, tmp_tbl, no_begin, no_end)
else
pre_intrusion = sumprot//2; post_intrusion = sumprot - pre_intrusion
end
- p = enlarge(p, rwidth, ppre, pmid, ppost, pre_intrusion, post_intrusion)
+ p, pre_protrusion, post_protrusion = enlarge(p, rwidth, ppre, pmid, ppost, pre_intrusion, post_intrusion)
pre_intrusion = min(mapre, pre_intrusion + round(ppre*getfield(p, 'glue_set')*65536))
post_intrusion = min(mapost, post_intrusion + round(ppost*getfield(p, 'glue_set')*65536))
else -- intmode == 4
@@ -354,7 +363,7 @@ local function enlarge_parent(r, p, tmp_tbl, no_begin, no_end)
else
pre_intrusion, post_intrusion = mapre, min(mapost, sumprot-mapre)
end
- p = enlarge(p, rwidth, ppre, pmid, ppost, pre_intrusion, post_intrusion)
+ p, pre_protrusion, post_protrusion = enlarge(p, rwidth, ppre, pmid, ppost, pre_intrusion, post_intrusion)
end
setshift(r, -pre_intrusion)
local rwidth = rwidth - pre_intrusion - post_intrusion
@@ -371,24 +380,29 @@ local function enlarge_parent(r, p, tmp_tbl, no_begin, no_end)
post_jfmgk = (post_intrusion > 0)
end
end
- return r, p, orig_post_intrusion, post_jfmgk
+ return r, p, orig_post_intrusion, post_jfmgk,
+ pre_protrusion - pre_intrusion, post_protrusion - post_intrusion
end
-- ルビボックスの生成(単一グループ)
-- returned value: <new box>, <ruby width>, <post_intrusion>
local max_margin
-local function new_ruby_box(r, p, tmp_tbl, no_begin, no_end)
+local function new_ruby_box(r, p, tmp_tbl, no_begin, no_end, w)
+ -- no_begin: 行頭形ではないか
+ -- no_end: 行末形ではないか
local post_intrusion, post_jfmgk = 0, false
local imode
local ppre, pmid, ppost = tmp_tbl.ppre, tmp_tbl.pmid, tmp_tbl.ppost
local mapre, mapost = tmp_tbl.mapre, tmp_tbl.mapost
local rpre, rmid, rpost, rsmash
+ local protrusion = {0, 0}; tmp_tbl[tmp_tbl.index] = protrusion
imode = tmp_tbl.mode//0x100000; rsmash = (imode%2 ==1)
imode = imode//2; rpost = imode%8;
imode = (imode-rpost)/8; rmid = imode%8;
imode = (imode-rmid)/8; rpre = imode%8
if getwidth(r) > getwidth(p) then -- change the width of p
- r, p, post_intrusion, post_jfmgk = enlarge_parent(r, p, tmp_tbl, no_begin, no_end)
+ r, p, post_intrusion, post_jfmgk, protrusion[1], protrusion[2]
+ = enlarge_parent(r, p, tmp_tbl, no_begin, no_end)
elseif getwidth(r) < getwidth(p) then -- change the width of r
r = enlarge(r, getwidth(p), rpre, rmid, rpost, 0, 0)
post_intrusion = 0
@@ -406,7 +420,7 @@ local function new_ruby_box(r, p, tmp_tbl, no_begin, no_end)
end
if need_repack then
local rt = r
- r = hpack(getlist(r), getwidth(r), 'exactly')
+ r = node_inherit_attr(hpack(getlist(r), getwidth(r), 'exactly'), r)
setlist(rt, nil); node_free(rt);
end
end
@@ -416,7 +430,8 @@ local function new_ruby_box(r, p, tmp_tbl, no_begin, no_end)
insert_after(r, k, p); setnext(p, nil)
if tmp_tbl.rubydepth >= 0 then setdepth(r, tmp_tbl.rubydepth) end
if tmp_tbl.baseheight >= 0 then setheight(p, tmp_tbl.baseheight) end
- a = node.direct.vpack(r); setshift(a, 0)
+ a = node_inherit_attr(node.direct.vpack(r), p)
+ setshift(a, 0)
set_attr(a, attr_ruby, post_intrusion)
set_attr(a, attr_ruby_post_jfmgk, post_jfmgk and 1 or 0)
if rsmash or getheight(a)<getheight(p) then
@@ -437,7 +452,10 @@ local max_allow_pre, max_allow_post
local flush_list = node.direct.flush_list
-- 中付き熟語ルビ,cmp containers
-- 「文字の構成を考えた」やつはどうしよう
-local function pre_low_cal_box(w, cmp)
+local pre_low_cal_box
+do
+ local node_prev = node.direct.getprev
+pre_low_cal_box = function (w, cmp)
local rb = {}
local pb = {}
local kf = {}
@@ -450,18 +468,24 @@ local function pre_low_cal_box(w, cmp)
local coef = {} -- 連立一次方程式の拡大係数行列
local rtb = expand_3bits(rst.stretch)
+ local kb, ka
+ if rst.quirk_protrusion then
+ kb = node_prev(node_tail(wv)); ka = node_next(kb)
+ node_remove(wv, kb); node_remove(wv, ka)
+ end
-- node list 展開・行末形の計算
local nt, nta, ntb = wv, nil, nil -- nt*: node temp
rst.ppre, rst.pmid, rst.ppost = rtb[6], rtb[5], rtb[4]
rst.mapre, rst.mapost = max_allow_pre, 0
- for i = 1, cmp do
+ for i = 1, cmp do
nt = node_next(nt); rb[i] = nt; nta = concat(nta, node_copy(nt))
nt = node_next(nt); pb[i] = nt; ntb = concat(ntb, node_copy(nt))
coef[i] = {}
for j = 1, 2*i do coef[i][j] = 1 end
for j = 2*i+1, 2*cmp+1 do coef[i][j] = 0 end
+ rst.index = i
kf[i], coef[i][2*cmp+2]
- = new_ruby_box(node_copy(nta), node_copy(ntb), rst, true, false)
+ = new_ruby_box(node_copy(nta), node_copy(ntb), rst, true, false, w)
end
node_free(nta); node_free(ntb)
@@ -474,8 +498,9 @@ local function pre_low_cal_box(w, cmp)
for j = 1, 2*i-1 do coef[cmp+i][j] = 0 end
for j = 2*i, 2*cmp+1 do coef[cmp+i][j] = 1 end
nta = concat(node_copy(rb[i]), nta); ntb = concat(node_copy(pb[i]), ntb)
+ rst.index = 2*cmp+1-i
kf[cmp+i], coef[cmp+i][2*cmp+2]
- = new_ruby_box(node_copy(nta), node_copy(ntb), rst, false, true)
+ = new_ruby_box(node_copy(nta), node_copy(ntb), rst, false, true, w)
end
-- ここで,nta, ntb には全 container を連結した box が入っているので
@@ -484,13 +509,17 @@ local function pre_low_cal_box(w, cmp)
for j = 1, 2*cmp+1 do coef[2*cmp+1][j] = 1 end
rst.ppre, rst.pmid, rst.ppost = rtb[3], rtb[2], rtb[1]
rst.mapre, rst.mapost = max_allow_pre, max_allow_post
+ rst.index = 2*cmp+1
kf[2*cmp+1], coef[2*cmp+1][2*cmp+2], post_intrusion_backup, post_jfmgk_backup
- = new_ruby_box(nta, ntb, rst, true, true)
+ = new_ruby_box(nta, ntb, rst, true, true, w)
-- w.value の node list 更新.
local nt = wv
flush_list(node_next(wv))
for i = 1, 2*cmp+1 do setnext(nt, kf[i]); nt = kf[i] end
+ if rst.quirk_protrusion then
+ insert_after(wv, nt, kb); insert_after(wv, kb, ka);
+ end
if cmp==1 then solve_1(coef)
elseif cmp==2 then solve_2(coef)
@@ -499,6 +528,7 @@ local function pre_low_cal_box(w, cmp)
end
return coef
end
+end
local first_whatsit
do
@@ -512,25 +542,40 @@ do
end
local next_cluster_array = {}
+local pre_high
-- ノード追加
-local function pre_low_app_node(head, w, cmp, coef, ht, dp)
+do
+ local node_prev = node.direct.getprev
+ local KINSOKU = luatexja.icflag_table.KINSOKU
+ local function pre_low_app_node (head, w, cmp, coef, ht, dp)
-- メインの node list 更新
- local nt = node_new(id_glue)
+ local nt = node_new(id_glue, nil, w) -- INHERIT ATTRIBUTES OF w
setglue(nt, coef[1][2*cmp+2], 0, 0, 0, 0)
set_attr(nt, attr_ruby, 1); set_attr(w, attr_ruby, 2)
head = insert_before(head, w, nt)
nt = w
for i = 1, cmp do
-- rule
- local nta = node_new(id_rule, 0);
+ local nta = node_new(id_rule, 0, w); -- INHERIT ATTRIBUTES OF w
setwhd(nta, coef[i*2][2*cmp+2], ht, dp)
insert_after(head, nt, nta)
set_attr(nta, attr_ruby, 2*i+1)
-- glue
if i~=cmp or not next_cluster_array[w] then
- nt = node_new(id_glue); insert_after(head, nta, nt)
+ nt = node_new(id_glue, nil, w); -- INHERIT ATTRIBUTE OF w
+ insert_after(head, nta, nt)
else
- nt = next_cluster_array[w]
+ nt = next_cluster_array[w]; local f = node_next(nta)
+ while f and f~=nt do
+ if getid(f)==id_glue then
+ node_remove(head, nt); insert_before(head, f, nt); f = nil
+ else if getid(f)==id_penalty and get_attr_icflag(f)==KINSOKU then
+ node_inherit_attr(f, w) -- INHERIT ATTRIBUTE OF w; for lua-ul
+ set_attr(f, attr_icflag, KINSOKU)
+ end
+ f = node_next(f)
+ end
+ end
end
setglue(nt, coef[i*2+1][2*cmp+2], 0, 0, 0, 0)
set_attr(nt, attr_ruby, 2*i+2)
@@ -540,14 +585,13 @@ local function pre_low_app_node(head, w, cmp, coef, ht, dp)
next_cluster_array[w]=nil
return head, first_whatsit(node_next(nt))
end
-
-local function pre_high(ahead)
+pre_high = function (ahead)
if not ahead then return ahead end
local head = to_direct(ahead)
post_intrusion_backup, post_jfmgk_backup = 0, false
local n = first_whatsit(head)
while n do
- if getsubtype(n) == sid_user and getfield(n, 'user_id') == RUBY_PRE then
+ if getsubtype(n) == sid_user and getfield(n, 'user_id') == RUBY_PRE then
local nv = getvalue(n)
local rst = getvalue(nv)
max_allow_pre = rst.pre or 0
@@ -567,13 +611,13 @@ local function pre_high(ahead)
if rst.exclude_pre_jfmgk_from_prev_ruby
and atr>0 and ((old_break_info[atr] or post_intrusion_backup) > 0) then
-- 「直前のルビが文字に進入→現在のルビの和文処理グルーへの進入はなし」という状況
- rst.before_jfmgk = 0
+ max_allow_pre = 0;rst.before_jfmgk = 0
end
post_intrusion_backup, post_jfmgk_backup = 0, false
max_allow_post = rst.post or 0
max_margin = rst.maxmargin or 0
local coef = pre_low_cal_box(n, rst.count)
- local s = node_tail(nv) --ルビ文字
+ local s = node_tail(nv); if rst.quirk_protrusion then s = node_prev(node_prev(s)) end --ルビ文字
head, n = pre_low_app_node(
head, n, rst.count, coef, getheight(s), getdepth(s)
)
@@ -583,11 +627,11 @@ local function pre_high(ahead)
end
return to_node(head)
end
+end
luatexbase.add_to_callback('pre_linebreak_filter', pre_high, 'ltj.ruby.pre', 100)
-luatexbase.add_to_callback('hpack_filter', pre_high, 'ltj.ruby.pre', 100)
----------------------------------------------------------------
--- post_line_break
+-- post_linebreak
----------------------------------------------------------------
local post_lown
do
@@ -595,47 +639,110 @@ do
local id = get_attr(wv, attr_ruby_id) or 0
if id>0 and cache_handle then
cache_handle:write(
- 'lrob[' .. tostring(id) .. ']=' .. num .. '\nlrob[' .. tostring(-id) .. ']=' .. tostring(bool) .. '\n')
+ 'lrob[' .. tostring(id) .. ']=' .. tostring(num) .. '\nlrob[' .. tostring(-id) .. ']=' .. tostring(bool) .. '\n')
end
end
-
+ local node_prev = node.direct.getprev
+ local function new_kern(inherit, num)
+ local k = node_new(id_kern, 1, inherit); setkern(k, num); set_attr(kt, attr_icflag, PROCESSED);
+ return k;
+ end
post_lown = function (rs, rw, cmp, ch)
-- ch: the head of `current' hlist
if #rs ==0 or not rw then return ch end
local hn = get_attr(rs[1], attr_ruby)
local fn = get_attr(rs[#rs], attr_ruby)
- local wv = getvalue(rw)
+ local wv = getvalue(rw); local rst = getvalue(wv)
if hn==1 then
if fn==2*cmp+2 then
- local hn = node_tail(wv)
- node_remove(wv, hn)
- insert_after(ch, rs[1], hn)
- set_attr(hn, attr_icflag, PROCESSED)
- write_aux(wv, get_attr(hn, attr_ruby), get_attr(hn, attr_ruby_post_jfmgk))-- 行中形
+ -- 行中形
+ local nn = node_tail(wv);
+ if rst.quirk_protrusion then
+ local prot_b,prot_a = rst[fn-1][1], rst[fn-1][2]
+ local ka=nn; local kb = node_prev(nn); nn = node_prev(kb)
+ node_remove(wv, nn); node_remove(wv, kb); node_remove(wv, ka)
+ if prot_b~=0 then
+ setkern(kb, prot_b); insert_after(ch, rs[1], kb);
+ local kt = new_kern(rw, -prot_b); insert_after(ch, kb, kt);
+ insert_after(ch, kt, nn);
+ else
+ node_free(kb); insert_after(ch, rs[1], nn)
+ end
+ if prot_a~=0 then
+ local kt = new_kern(rw, -prot_a); insert_after(ch, nn, kt);
+ setkern(ka, prot_a); insert_after(ch, kt, ka);
+ else node_free(ka)
+ end
+ else
+ node_remove(wv, nn); insert_after(ch, rs[1], nn)
+ end
+ set_attr(nn, attr_icflag, PROCESSED)
+ write_aux(wv, get_attr(nn, attr_ruby), get_attr(nn, attr_ruby_post_jfmgk))
else
- local deg, hn = (fn-1)/2, wv
- for i = 1, deg do hn = node_next(hn) end;
- node_remove(wv, hn)
- setnext(hn, nil)
- insert_after(ch, rs[1], hn)
- set_attr(hn, attr_icflag, PROCESSED)
- write_aux(wv, get_attr(hn, attr_ruby), get_attr(hn, attr_ruby_post_jfmgk))
+ -- 行末形
+ local deg, nn = (fn-1)/2, wv; for i = 1, deg do nn = node_next(nn) end
+ if rst.quirk_protrusion then
+ local prot_b = rst[deg][1]
+ local ka = node_tail(wv); local kb = node_prev(ka);
+ node_remove(wv, nn); setnext(nn, nil); node_remove(wv, kb);
+ if prot_b~=0 then
+ setkern(kb, prot_b); insert_after(ch, rs[1], kb);
+ local kt = new_kern(rw, -prot_b); insert_after(ch, kb, kt);
+ insert_after(ch, kt, nn);
+ else
+ node_free(kb); insert_after(ch, rs[1], nn)
+ end
+ if deg==cmp then
+ local prot_a = rst[deg][2]; node_remove(wv,ka)
+ if prot_a~=0 then
+ local kt = new_kern(rw, -prot_a); insert_after(ch, nn, kt);
+ setkern(ka, prot_a); insert_after(ch, kt, ka);
+ else node_free(ka)
+ end
+ end
+ else
+ node_remove(wv, nn); setnext(nn, nil); insert_after(ch, rs[1], nn)
+ end
+
+ set_attr(nn, attr_icflag, PROCESSED)
+ write_aux(wv, get_attr(nn, attr_ruby), get_attr(nn, attr_ruby_post_jfmgk))
end
else
- local deg, hn = max((hn-1)/2,2), wv
- for i = 1, cmp+deg-1 do hn = node_next(hn) end
+ -- 行頭形
+ local nn = wv; for i = 1, cmp+max((hn-1)/2,2)-1 do nn = node_next(nn) end
-- -1 is needed except the case hn = 3,
-- because a ending-line form is removed already from the list
- node_remove(wv, hn); setnext(hn, nil)
- insert_after(ch, rs[1], hn)
- set_attr(hn, attr_icflag, PROCESSED)
+ if rst.quirk_protrusion then
+ local deg=(hn-1)/2; local prot_b = rst[2*cmp+1-deg][1]
+ local ka = node_tail(wv); node_remove(wv, nn); setnext(nn, nil);
+ if deg==1 then
+ local kb = node_prev(ka); node_remove(wv, kb);
+ if prot_b~=0 then
+ setkern(kb, prot_b); insert_after(ch, rs[1], kb);
+ local kt = new_kern(rw, -prot_b); insert_after(ch, kb, kt);
+ insert_after(ch, kt, nn);
+ else
+ node_free(kb); insert_after(ch, rs[1], nn)
+ end
+ else insert_after(ch, rs[1], nn)
+ end
+ local prot_a = rst[2*cmp+1-deg][2]; node_remove(wv,ka)
+ if prot_a~=0 then
+ local kt = new_kern(rw, -prot_a); insert_after(ch, nn, kt);
+ setkern(ka, prot_a); insert_after(ch, kt, ka);
+ else node_free(ka)
+ end
+ else
+ node_remove(wv, nn); setnext(nn, nil); insert_after(ch, rs[1], nn)
+ end
+
+ set_attr(nn, attr_icflag, PROCESSED)
if fn == 2*cmp-1 then
- write_aux(wv, get_attr(hn, attr_ruby), get_attr(hn, attr_ruby_post_jfmgk))
+ write_aux(wv, get_attr(nn, attr_ruby), get_attr(nn, attr_ruby_post_jfmgk))
end
end
for i = 1,#rs do
- local ri = rs[i]
- ch = node_remove(ch, ri); node_free(ri);
+ local ri = rs[i]; ch = node_remove(ch, ri); node_free(ri)
end
-- cleanup
if fn >= 2*cmp+1 then node_free(rw) end
@@ -644,73 +751,86 @@ do
end
local traverse_id = node.direct.traverse_id
-local function post_high_break(head)
- local rs = {} -- rs: sequence of ruby_nodes,
- local rw = nil -- rw: main whatsit
- local cmp = -2 -- dummy
- for h in traverse_id(id_hlist, to_direct(head)) do
- for i = 1, #rs do rs[i] = nil end
- local ha = getlist(h)
+local post_high_hbox, post_high_break
+do
+ local rs, rw = {}, nil -- rs: sequence of ruby_nodes, rw: main whatsit
+ local cmp
+ post_high_break = function (head)
+ for h in traverse_id(id_hlist, to_direct(head)) do
+ for i = 1, #rs do rs[i] = nil end
+ local ha = getlist(h);
+ while ha do
+ local hai = getid(ha)
+ local i = ((hai == id_glue and getsubtype(ha)==0)
+ or (hai == id_rule and getsubtype(ha)==0)
+ or (hai == id_whatsit and getsubtype(ha)==sid_user
+ and getfield(ha, 'user_id', RUBY_POST)))
+ and get_attr(ha, attr_ruby) or 0
+ if i==0 then
+ ha = node_next(ha)
+ elseif i==1 then
+ setlist(h, post_lown(rs, rw, cmp, getlist(h)))
+ for i = 2, #rs do rs[i] = nil end -- rs[1] is set by the next statement
+ rs[1], rw = ha, nil; ha = node_next(ha)
+ elseif i==2 then
+ rw = ha
+ cmp = getvalue(getvalue(rw)).count
+ local hb, hc = node_remove(getlist(h), rw)
+ setlist(h, hb); ha = hc
+ else -- i>=3
+ rs[#rs+1] = ha; ha = node_next(ha)
+ end
+ end
+ setlist(h, post_lown(rs, rw, cmp, getlist(h)))
+ end
+ return head
+ end
+ post_high_hbox = function (ahead)
+ for i = 1, #rs do rs[i] = nil end; rw = nil
+ local ha = to_direct(ahead); local head = ha
while ha do
local hai = getid(ha)
local i = ((hai == id_glue and getsubtype(ha)==0)
- or (hai == id_rule and getsubtype(ha)==0)
- or (hai == id_whatsit and getsubtype(ha)==sid_user
- and getfield(ha, 'user_id', RUBY_POST)))
- and get_attr(ha, attr_ruby) or 0
+ or (hai == id_rule and getsubtype(ha)==0)
+ or (hai == id_whatsit and getsubtype(ha)==sid_user
+ and getfield(ha, 'user_id', RUBY_POST)))
+ and get_attr(ha, attr_ruby) or 0
if i==0 then
ha = node_next(ha)
elseif i==1 then
- setlist(h, post_lown(rs, rw, cmp, getlist(h)))
+ head = post_lown(rs, rw, cmp, head)
for i = 2, #rs do rs[i] = nil end -- rs[1] is set by the next statement
rs[1], rw = ha, nil; ha = node_next(ha)
elseif i==2 then
rw = ha
cmp = getvalue(getvalue(rw)).count
- local hb, hc = node_remove(getlist(h), rw)
- setlist(h, hb); ha = hc
- else -- i>=3
+ head, ha = node_remove(head, rw)
+ else -- i >= 3
rs[#rs+1] = ha; ha = node_next(ha)
end
end
- setlist(h, post_lown(rs, rw, cmp, getlist(h)))
+ return to_node(post_lown(rs, rw, cmp, head))
end
- return head
end
-
-local function post_high_hbox(ahead)
- local ha = to_direct(ahead); local head = ha
- local rs = {}; -- rs: sequence of ruby_nodes,
- local rw = nil; -- rw: main whatsit
- local cmp
- while ha do
- local hai = getid(ha)
- local i = ((hai == id_glue and getsubtype(ha)==0)
- or (hai == id_rule and getsubtype(ha)==0)
- or (hai == id_whatsit and getsubtype(ha)==sid_user
- and getfield(ha, 'user_id', RUBY_POST)))
- and get_attr(ha, attr_ruby) or 0
- if i==0 then
- ha = node_next(ha)
- elseif i==1 then
- head = post_lown(rs, rw, cmp, head)
- for i = 2, #rs do rs[i] = nil end -- rs[1] is set by the next statement
- rs[1], rw = ha, nil; ha = node_next(ha)
- elseif i==2 then
- rw = ha
- cmp = getvalue(getvalue(rw)).count
- head, ha = node_remove(head, rw)
- else -- i >= 3
- rs[#rs+1] = ha; ha = node_next(ha)
- end
+do
+ -- pre_append_to_vlist_filter.lua: distributed with lua-ul
+ local found = kpse.find_file('pre_append_to_vlist_filter.lua', 'lua')
+ if not found then
+ luatexbase.add_to_callback('post_linebreak_filter', post_high_break, 'ltj.ruby.post_break')
+ else
+ require 'pre_append_to_vlist_filter'
+ luatexbase.add_to_callback('pre_append_to_vlist_filter',
+ function(head, loc)
+ return (loc~='post_linebreak') and head or post_high_break(head)
+ end,
+ 'ltj.ruby.post_break',
+ (luatexbase.priority_in_callback('pre_append_to_vlist_filter', 'add underlines to list') or 1))
end
- return to_node(post_lown(rs, rw, cmp, head))
+ luatexbase.add_to_callback('hpack_filter',
+ function(head) return post_high_hbox(pre_high(head)) end, 'ltj.ruby',
+ luatexbase.priority_in_callback('hpack_filter', 'add underlines to list') or nil)
end
-luatexbase.add_to_callback('post_linebreak_filter', post_high_break, 'ltj.ruby.post_break', 100)
-luatexbase.add_to_callback('hpack_filter', post_high_hbox, 'ltj.ruby.post_hbox', 101)
-
-
----------------------------------------------------------------
-- for jfmglue callbacks
----------------------------------------------------------------
@@ -736,7 +856,7 @@ do
p = 0
end
rst.pre = -p; rst.exclude_pre_from_prev_ruby = (s<0);
- rst.exclude_pre_jfmgk_from_prev_ruby = (ltjs.table_current_stack[RIPOST +Nq.char] or 0)<0;
+ rst.exclude_pre_jfmgk_from_prev_ruby = (ltjs.table_current_stack[RIPOST +Nq.char] or 0)<0;
end
if Nq.prev_ruby then
set_attr(lp, attr_ruby, Nq.prev_ruby)
@@ -758,6 +878,11 @@ do
elseif rst.pre < 0 then -- auto
rst.pre = 0
end
+ if rst.quirk_protrusion then
+ local lk = node_new(id_kern, 1, Nq.nuc, lp); set_attr(lk, attr_icflag, PROCESSED)
+ insert_after(lpv, node_tail(lpv), lk)
+ insert_after(lpv, node_tail(lpv), node_new(id_kern, 1))
+ end
return Np
else
return Np
@@ -780,10 +905,12 @@ do
end
local RIPOST = luatexja.stack_table_index.RIPOST
local abs = math.abs
+ local ltjj_after_hlist=luatexja.jfmglue.after_hlist
+ local ltjj_check_box_high=luatexja.jfmglue.check_box_high
local function whatsit_after_callback(s, Nq, Np, head)
if not s and getfield(Nq.nuc, 'user_id') == RUBY_PRE then
if Np then
- local last_glue = node_new(id_glue)
+ local last_glue = node_new(id_glue, nil, Nq.nuc) -- INHERIT ATTRIBUTE OF Nq.nuc
set_attr(last_glue, attr_icflag, 0)
insert_before(Nq.nuc, Np.first, last_glue)
Np.first = last_glue
@@ -798,8 +925,8 @@ do
end
local x = node_next(node_next(nqnv))
for i = 2, rst.count do x = node_next(node_next(x)) end
- Nq.last_char = luatexja.jfmglue.check_box_high(Nq, getlist(x), nil)
- luatexja.jfmglue.after_hlist(Nq)
+ Nq.last_char = ltjj_check_box_high(Nq, getlist(x), nil)
+ ltjj_after_hlist(Nq)
if Np and Np.id ~=id_pbox_w and type(Np.char)=='number' then
-- Np is a JAchar
if rst.post < 0 then -- auto
@@ -812,12 +939,15 @@ do
Np.prev_ruby = get_attr(getvalue(Nq.nuc), attr_ruby_id)
-- 前のクラスタがルビであったことのフラグ
else -- 直前が文字以外
- local nqnv = getvalue(Nq.nuc)
- local rst = getvalue(nqnv)
if rst.post < 0 then -- auto
rst.post = 0
end
end
+ if rst.quirk_protrusion then
+ local lk = node_tail(nqnv);
+ node_inherit_attr(lk, Nq.nuc, Np and Np.nuc)
+ set_attr(lk, attr_icflag, PROCESSED)
+ end
return head
else
return s
diff --git a/Master/texmf-dist/tex/luatex/luatexja/ltjsarticle.cls b/Master/texmf-dist/tex/luatex/luatexja/ltjsarticle.cls
index 5de7ff1e774..813f7d1aab6 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/ltjsarticle.cls
+++ b/Master/texmf-dist/tex/luatex/luatexja/ltjsarticle.cls
@@ -38,7 +38,7 @@
%% Right brace \} Tilde \~}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{ltjsarticle}
- [2022/09/12 ltjsclasses ]
+ [2023/07/26 ltjsclasses ]
\def\jsc@clsname{ltjsarticle}
\def\Cjascale{0.924715}
\RequirePackage{luatexja}
diff --git a/Master/texmf-dist/tex/luatex/luatexja/ltjsbook.cls b/Master/texmf-dist/tex/luatex/luatexja/ltjsbook.cls
index 99480233056..3a156891c88 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/ltjsbook.cls
+++ b/Master/texmf-dist/tex/luatex/luatexja/ltjsbook.cls
@@ -38,7 +38,7 @@
%% Right brace \} Tilde \~}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{ltjsbook}
- [2022/09/12 ltjsclasses ]
+ [2023/07/26 ltjsclasses ]
\def\jsc@clsname{ltjsbook}
\def\Cjascale{0.924715}
\RequirePackage{luatexja}
diff --git a/Master/texmf-dist/tex/luatex/luatexja/ltjskiyou.cls b/Master/texmf-dist/tex/luatex/luatexja/ltjskiyou.cls
index 231be8bf2ef..5f62215f940 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/ltjskiyou.cls
+++ b/Master/texmf-dist/tex/luatex/luatexja/ltjskiyou.cls
@@ -38,7 +38,7 @@
%% Right brace \} Tilde \~}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{ltjskiyou}
- [2022/09/12 ltjsclasses ]
+ [2023/07/26 ltjsclasses ]
\def\jsc@clsname{ltjskiyou}
\def\Cjascale{0.924715}
\RequirePackage{luatexja}
diff --git a/Master/texmf-dist/tex/luatex/luatexja/ltjspf.cls b/Master/texmf-dist/tex/luatex/luatexja/ltjspf.cls
index 2723db71cac..730bc082b22 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/ltjspf.cls
+++ b/Master/texmf-dist/tex/luatex/luatexja/ltjspf.cls
@@ -38,7 +38,7 @@
%% Right brace \} Tilde \~}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{ltjspf}
- [2022/09/12 ltjsclasses ]
+ [2023/07/26 ltjsclasses ]
\def\jsc@clsname{ltjspf}
\def\Cjascale{0.903375}
\RequirePackage{luatexja}
diff --git a/Master/texmf-dist/tex/luatex/luatexja/ltjsreport.cls b/Master/texmf-dist/tex/luatex/luatexja/ltjsreport.cls
index 5fb4691762f..08ed724da15 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/ltjsreport.cls
+++ b/Master/texmf-dist/tex/luatex/luatexja/ltjsreport.cls
@@ -38,7 +38,7 @@
%% Right brace \} Tilde \~}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{ltjsreport}
- [2022/09/12 ltjsclasses ]
+ [2023/07/26 ltjsclasses ]
\def\jsc@clsname{ltjsreport}
\def\Cjascale{0.924715}
\RequirePackage{luatexja}
diff --git a/Master/texmf-dist/tex/luatex/luatexja/luatexja.lua b/Master/texmf-dist/tex/luatex/luatexja/luatexja.lua
index 1013684496a..e815ba3d682 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/luatexja.lua
+++ b/Master/texmf-dist/tex/luatex/luatexja/luatexja.lua
@@ -423,9 +423,10 @@ local utfchar = utf.char
local function debug_show_node_X(p,print_fn, limit, inner_depth)
local k = prefix
local s
- local pt, pic = node_type(p.id), (get_attr(p, attr_icflag) or 0) % icflag_table.PROCESSED_BEGIN_FLAG
- local base = prefix .. '[' .. string.format('%7d', node.direct.todirect(p)) .. '] ' ..
- string.format('%X', pic) .. ' ' .. pt .. ' ' .. tostring(p.subtype) .. ' '
+ local pt, pic = node_type(p.id), (get_attr(p, attr_icflag) or 0) --% icflag_table.PROCESSED_BEGIN_FLAG
+ local base = prefix .. '[' .. string.format('%7d', node.direct.todirect(p))
+ .. ', ' .. tostring(get_attr(p, 27)) .. '] '
+ .. string.format('%X', pic) .. ' ' .. pt .. ' ' .. tostring(p.subtype) .. ' '
if pt == 'glyph' then
s = base .. ' '
.. (p.char<0xF0000 and utfchar(p.char) or '')
diff --git a/Master/texmf-dist/tex/luatex/luatexja/luatexja.sty b/Master/texmf-dist/tex/luatex/luatexja/luatexja.sty
index a54ede6758b..90bb4fdf7e3 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/luatexja.sty
+++ b/Master/texmf-dist/tex/luatex/luatexja/luatexja.sty
@@ -27,7 +27,7 @@
\newif\ifltj@disablejfam
%%%% VERSION
-\def\LuaTeXjaversion{20240514.0}
+\def\LuaTeXjaversion{20240909.0}
%% Check if LaTeX is used.
\begingroup\expandafter\expandafter\expandafter\endgroup
diff --git a/Master/texmf-dist/tex/luatex/luatexja/patches/lltjcore.sty b/Master/texmf-dist/tex/luatex/luatexja/patches/lltjcore.sty
index 1c8f9cba4ef..121a45ba0b1 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/patches/lltjcore.sty
+++ b/Master/texmf-dist/tex/luatex/luatexja/patches/lltjcore.sty
@@ -219,10 +219,6 @@
\@latex@error{Direction change inside float!?\MessageBreak
Use \noexpand\layoutcaption provided in \string\usepackage{lltjext}}\@ehc}
%%% Remove extra xkanjiskip
-\renewcommand\@makefnmark{%
- \unless\ifnum\ltjgetparameter{direction}=3
- \hbox{}\hbox{\@textsuperscript{\normalfont\@thefnmark}}\hbox{}%
- \else\hbox{\yoko \@textsuperscript{\normalfont\@thefnmark}}\fi}
\begingroup
\@ifpackageloaded{hyperref}
{\ifdefined\real@setref\def\ltj@setrefprefix{real}\else\def\ltj@setrefprefix{}\fi}
@@ -250,6 +246,11 @@
\gdef\@stopfield{%
\inhibitglue\@tempskipa\lastskip\unskip
\hskip\@tempskipa\color@endgroup\egroup}
+%%%%%% footnote
+\renewcommand\@makefnmark{%
+ \unless\ifnum\ltjgetparameter{direction}=3
+ \hbox{}\hbox{\@textsuperscript{\normalfont\@thefnmark}}\hbox{}%
+ \else\hbox{\yoko \@textsuperscript{\normalfont\@thefnmark}}\fi}
\pretocmd{\footnote}{\inhibitglue}{}{}
\pretocmd{\footnotemark}{\inhibitglue}{}{}
\def\@ltj@process@makefnmark#1{%
diff --git a/Master/texmf-dist/tex/luatex/luatexja/patches/lltjdefs.sty b/Master/texmf-dist/tex/luatex/luatexja/patches/lltjdefs.sty
index bb63ac68774..00c858e3493 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/patches/lltjdefs.sty
+++ b/Master/texmf-dist/tex/luatex/luatexja/patches/lltjdefs.sty
@@ -3,7 +3,7 @@
%
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{lltjdefs}[2022-01-23 Default font settings of LuaTeX-ja]
+\ProvidesPackage{lltjdefs}[2024-05-16 Default font settings of LuaTeX-ja]
\ifdefined\ltj@stdmcfont\else\def\ltj@stdmcfont{file:HaranoAjiMincho-Regular.otf}\fi
\ifdefined\ltj@stdgtfont\else\def\ltj@stdgtfont{file:HaranoAjiGothic-Medium.otf}\fi
@@ -18,13 +18,8 @@
\DeclareKanjiEncodingDefaults{}{}
\DeclareErrorKanjiFont{JY3}{mc}{m}{n}{10}
\kanjifamily{mc}
-\ifnum\ltj@@latex@plv<1500 % <=2020-10-01
- \kanjiseries{m}
- \kanjishape{n}
-\else % >=2021-06-01
- \def\k@series{m}
- \def\k@shape{n}
-\fi
+\def\k@series{m}
+\def\k@shape{n}
\fontsize{10}{10}
\DeclareYokoKanjiEncoding{JY3}{}{}
\DeclareKanjiSubstitution{JY3}{mc}{m}{n}
@@ -37,12 +32,7 @@
\newcommand\kanjiencodingdefault{JY3}
\newcommand\kanjifamilydefault{\mcdefault}
\newcommand\kanjiseriesdefault{\mddefault}
-\ifnum 0\ifltj@ltfilehook@avail1\fi\ifdefined\@rmfamilyhook1\fi>0
- %% LaTeX 2020-02-02
- \newcommand\kanjishapedefault{\shapedefault}
-\else%% LaTeX 2019-10-01
- \newcommand\kanjishapedefault{\updefault}
-\fi
+\newcommand\kanjishapedefault{\shapedefault}
\DeclareKanjiFamily{JY3}{mc}{}
\DeclareFontShape{JY3}{mc}{m}{n}{<-> s*[\ifdefined\Cjascale\Cjascale\else 0.962216\fi]
@@ -90,57 +80,36 @@
\DeclareMathAlphabet{\mathgt}{JY3}{gt}{m}{n}
\fi
-\ifnum 0\ifltj@ltfilehook@avail1\fi\ifdefined\@rmfamilyhook1\fi>0
-%%%% LaTeX >= 2020-02-02
\edef\bfseries@mc{\bfdefault}
\edef\bfseries@gt{\bfdefault}
\def\bfseries@jtt{\bfseries@mc}
\edef\mdseries@mc{\mddefault}
\edef\mdseries@gt{\mddefault}
\def\mdseries@jtt{\mdseries@mc}
-\fi
\newif\if@ltj@match@family
\@ltj@match@familyfalse
\def\verbatim@font{\normalfont\ttfamily\kanjifamily\jttdefault\selectfont}
-\def\@ltj@hook@family#1#2{% #1: csname #2: contents
- \ifltj@ltfilehook@avail % LaTeX 2020-10-01
- \AddToHook{#1}{#2}%
- \else\ifcsname @#1hook\endcsname % LaTeX 2020-02-02
- \csappto{@#1hook}{#2}%
- \else % LaTeX 2019-10-01
- \ifcsname #1 \endcsname
- \expandafter\patchcmd\csname #1 \endcsname{\selectfont}{#2\selectfont}{}{}%
- \else
- \PackageWarningNoLine{luatexja}{%
- Patching to \expandafter\string\csname #1\endcsname\space failed%
- }%
- \fi
- \fi\fi
-}
-\@ltj@hook@family{rmfamily}{%
+\AddToHook{rmfamily}{%
\if@ltj@match@family
\prepare@family@series@update@kanji{mc}\mcdefault
\fi
}
-\@ltj@hook@family{sffamily}{%
+\AddToHook{sffamily}{%
\if@ltj@match@family
\prepare@family@series@update@kanji{gt}\gtdefault
\fi
}
-\@ltj@hook@family{ttfamily}{%
+\AddToHook{ttfamily}{%
\if@ltj@match@family
\prepare@family@series@update@kanji{jtt}\jttdefault
\fi
}
-\let\@ltj@hook@family\@undefined
-\ifltj@ltfilehook@avail % 2020-10-01
- \expandafter\def\expandafter\kanjiseriesdefault
- \expandafter{\kanjiseriesdefault\@empty}
- \let\kanjiseriesdefault@kernel\kanjiseriesdefault
-\fi
+\expandafter\def\expandafter\kanjiseriesdefault
+ \expandafter{\kanjiseriesdefault\@empty}
+\let\kanjiseriesdefault@kernel\kanjiseriesdefault
%%% \eminnershape
\expandafter\patchcmd\csname em \endcsname{\itshape}{\gtfamily\itshape}{}{}
diff --git a/Master/texmf-dist/tex/luatex/luatexja/patches/lltjfont.sty b/Master/texmf-dist/tex/luatex/luatexja/patches/lltjfont.sty
index 2efc9435ab8..52ac44d5ccb 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/patches/lltjfont.sty
+++ b/Master/texmf-dist/tex/luatex/luatexja/patches/lltjfont.sty
@@ -3,31 +3,10 @@
%
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{lltjfont}[2023-04-13 Patch to NFSS2 for LuaTeX-ja]
+\ProvidesPackage{lltjfont}[2023-05-16 Patch to NFSS2 for LuaTeX-ja]
%%%%%%%% LaTeX2e version detection
-\newcount\ltj@@latex@plv \ltj@@latex@plv=-1
-\ifltj@ltfilehook@avail
-\ExplSyntaxOn
- \cs_if_exist:NTF \__shipout_execute_main_cont:Nnnn
- {\ltj@@latex@plv=1500}% 2021-06-01
- {\ifnum\patch@level>2\relax \ltj@@latex@plv=1300\else \ltj@@latex@plv=1000\fi}% 2020-10-01
-\ExplSyntaxOff
-\else\ifdefined\@rmfamilyhook % 2020-02-02
- \ifx\@forced@seriestrue\@undefined % 2020-02-02 pl0--2
- \@latex@error
- {Please update LaTeX2e!^^J\space\space
- At least LaTeX2e 2020-02-02 patch level 3 is required}%
- {LaTeX2e 2020-02-02 patch level 2 (and 4) has a bug.}
- \else
- \ltj@@latex@plv=300
- \unless\ifx\series@maybe@drop@one@m@x\@undefined % pl5 + develop
- \ltj@@latex@plv=501
- \else\unless\ifx\series@maybe@drop@one@m\@undefined % patch level 5
- \ltj@@latex@plv=500
- \fi\fi
- \fi
-\fi\fi
+\newcount\ltj@@latex@plv \ltj@@latex@plv=1500
%% patching \DeclareTextComposite
\def\ltj@chardef@text@cmd#1{%
@@ -400,59 +379,7 @@
\directlua{luatexja.jfont.pickup_alt_font_a('\f@size')}%
}%
\fi}
-\ifnum\ltj@@latex@plv<1500 % <=2020-10-01
-\protected\def\ltj@selectfont@patch{%
- \ltj@@start@time@measure{selectfont}%
- \let\tmp@error@fontshape\error@fontshape
- \let\error@fontshape\error@kfontshape
- \ltj@@is@kyenc{\k@encoding}\ifin@%
- \let\cy@encoding\k@encoding
- \ensure@KanjiEncodingPair{t}%
- \edef\ct@encoding{\csname t@enc@\k@encoding\endcsname}%
- \else
- \ltj@@is@ktenc{\k@encoding}\ifin@%
- \let\ct@encoding\k@encoding
- \ensure@KanjiEncodingPair{y}%
- \edef\cy@encoding{\csname y@enc@\k@encoding\endcsname}%
- \else
- \@latex@error{KANJI Encoding scheme `\k@encoding' unknown}\@eha
- \fi
- \fi
- \global\let\ltj@afont@name=\font@name
- \ltj@selectfont@tate\ltj@selectfont@yoko
-%
- \edef\tmp@item{{\k@encoding}}\expandafter\def\expandafter\k@encoding\tmp@item
- \kenc@update
- \global\let\font@name=\ltj@afont@name
- \let\error@fontshape\tmp@error@fontshape
- \if@knjcmd \@knjcmdfalse
- \expandafter\ifx
- \csname rel@\k@encoding/\k@family/\k@series/\k@shape\endcsname\relax
- \expandafter\ifx
- \csname rel@\k@encoding/\k@family/\k@series/all\endcsname\relax
- \else
- \csname rel@\k@encoding/\k@family/\k@series/all\endcsname\selectfont
- % 警告: 再び \selectfont を呼んでいる.無限ループの可能性あり
- \fi
- \else
- \csname rel@\k@encoding/\k@family/\k@series/\k@shape\endcsname\selectfont
- % 警告: 再び \selectfont を呼んでいる.無限ループの可能性あり
- \fi
- \fi
- \global\let\font@name=\ltj@afont@name
- \ltj@@stop@time@measure{selectfont}%
-}
-\RequirePackage{everysel}
-\let\ltj@@EverySelectfont@Init=\@EverySelectfont@Init
-\expandafter\expandafter\expandafter\let
-\expandafter\expandafter\csname ltj@@orig@selectfont\endcsname\csname selectfont\space\endcsname
-\@EverySelectfont@Init% for LaTeX2e <=2020-10-01
-\def\@EverySelectfont@Init{%
- \expandafter\let\csname selectfont\space \endcsname \ltj@@orig@selectfont
- \ltj@@EverySelectfont@Init
-}
-\EverySelectfont{\ltj@selectfont@patch}
-\else % LaTeX2e >=2021-06-01
+
\AddToHook{selectfont}[luatexja]{%
\ltj@@start@time@measure{selectfont}%
\ifx\delayed@k@adjustment\@empty
@@ -514,7 +441,6 @@
\global\let\font@name=\ltj@afont@name
\ltj@@stop@time@measure{selectfont}%
}
-\fi
\bgroup
\def\ltj@@dir@patch#1#2#3{%
@@ -721,8 +647,6 @@
}
%%%%%%
-\ifnum\ltj@@latex@plv>0
-%%%% LaTeX >= 2020-02-02
\newif\if@shape@roman@kanji
\def\merge@kanji@series#1{%
@@ -740,76 +664,11 @@
\@nil
}
-\ifnum\ltj@@latex@plv>500 % !!! pl5 + develop
\def\set@target@series@kanji#1{%
\edef\k@series{#1}%
\series@maybe@drop@one@m\k@series\k@series
}
-\else\ifnum\ltj@@latex@plv>300 % !!! pl5
- \def\set@target@series@kanji#1{%
- \edef\k@series{#1}%
- \expandafter\series@maybe@drop@one@m\expandafter{\k@series}\k@series
- }
-\else % !!! pl 3, 4
- \def\set@target@series@kanji#1{%
- \edef\k@series{#1}%
- \edef\k@series{\expandafter\series@drop@one@m\k@series mm\series@drop@one@m}%
- }
-\fi\fi
-\ifnum\ltj@@latex@plv<1500% <=2020-10-01
-\def\merge@kanji@series@#1#2#3\@nil{%
- \def\reserved@a{#3}%
- \ifx\reserved@a\@empty
- \set@target@series@kanji{#2}%
- \else
- \begingroup\let\f@encoding\k@encoding\let\f@family\k@family
- \maybe@load@fontshape\endgroup
- \edef\reserved@a{\k@encoding /\k@family /#1/\k@shape}%
- \ifcsname \reserved@a \endcsname
- \set@target@series@kanji{#1}%
- \else
- \ifcsname \k@encoding /\k@family /#2/\k@shape \endcsname
- \set@target@series@kanji{#2}%
- {\let\curr@fontshape\curr@kfontshape\@font@shape@subst@warning}%
- \else
- \set@target@series@kanji{#3}%
- {\let\curr@fontshape\curr@kfontshape\@font@shape@subst@warning}%
- \fi
- \fi
- \fi
-}
-\def\merge@kanji@shape@#1#2#3\@nil{%
- \def\reserved@a{#3}%
- \ifx\reserved@a\@empty
- \if@shape@roman@kanji
- \set@safe@kanji@shape{#2}{}%
- \else
- \edef\k@shape{#2}%
- \fi
- \else
- \begingroup\let\f@encoding\k@encoding\let\f@family\k@family
- \maybe@load@fontshape\endgroup
- \edef\reserved@a{\k@encoding /\k@family /\k@series/#1}%
- \ifcsname \reserved@a\endcsname
- \edef\k@shape{#1}%
- \else
- \ifcsname \k@encoding /\k@family /\k@series/#2\endcsname
- \edef\k@shape{#2}%
- {\let\curr@fontshape\curr@kfontshape\@font@shape@subst@warning}%
- \else
- \if@shape@roman@kanji
- \set@safe@kanji@shape{#3}%
- {{\let\curr@fontshape\curr@kfontshape\@font@shape@subst@warning}}%
- \else
- \edef\k@shape{#3}%
- {\let\curr@fontshape\curr@kfontshape\@font@shape@subst@warning}%
- \fi
- \fi
- \fi
- \fi
-}
-\else % >=2021-06-01
\def\merge@kanji@series@#1#2#3\@nil{%
\def\reserved@a{#3}%
\ifx\reserved@a\@empty
@@ -892,20 +751,8 @@
\fi
}
\let\delayed@merge@kanji@shape\merge@kanji@shape@without@substitution
-\fi
\newif\if@forced@series@kanji
-\ifnum\ltj@@latex@plv=300 % 2020-02-02 pl3, 4
- \DeclareRobustCommand\romanseries[1]{\merge@font@series{#1}}
- \DeclareRobustCommand\kanjiseries[1]{\merge@kanji@series{#1}}
- \DeclareRobustCommand\romanseriesforce[1]{\edef\f@series{#1}}
- \DeclareRobustCommand\kanjiseriesforce[1]{\edef\k@series{#1}}
-\else\ifnum\ltj@@latex@plv<1500% >=2020-02-02 pl5 and <=2020-10-01
- \DeclareRobustCommand\romanseries[1]{\@forced@seriesfalse\merge@font@series{#1}}
- \DeclareRobustCommand\kanjiseries[1]{\@forced@series@kanjifalse\merge@kanji@series{#1}}
- \DeclareRobustCommand\romanseriesforce[1]{\@forced@seriestrue\edef\f@series{#1}}
- \DeclareRobustCommand\kanjiseriesforce[1]{\@forced@series@kanjitrue\edef\k@series{#1}}
-\else% >=2021-06-01
\DeclareRobustCommand\romanseries[1]{\@forced@seriesfalse
\expandafter\def\expandafter\delayed@f@adjustment\expandafter
{\delayed@f@adjustment\delayed@merge@font@series{#1}}}
@@ -919,22 +766,9 @@
\expandafter\def\expandafter\delayed@k@adjustment\expandafter
{\delayed@k@adjustment\edef\k@series{#1}}}
\let\delayed@k@adjustment\@empty
-\fi\fi
\DeclareRobustCommand\fontseries[1]{\kanjiseries{#1}\romanseries{#1}}%
\DeclareRobustCommand\fontseriesforce[1]{\kanjiseriesforce{#1}\romanseriesforce{#1}}%
-\ifnum\ltj@@latex@plv<1500% <=2020-10-01
- \DeclareRobustCommand\romanshape[1]{\merge@font@shape{#1}}
- \DeclareRobustCommand\kanjishape[1]{\merge@kanji@shape{#1}}
- \DeclareRobustCommand\fontshape[1]{%
- \@shape@roman@kanjitrue
- \merge@font@shape{#1}\merge@kanji@shape{#1}%
- \@shape@roman@kanjifalse
- }
- \DeclareRobustCommand\romanshapeforce[1]{\edef\f@shape{#1}}
- \DeclareRobustCommand\kanjishapeforce[1]{\edef\k@shape{#1}}
- \DeclareRobustCommand\fontshapeforce[1]{\set@safe@kanji@shape{#1}{}\romanshapeforce{#1}}
-\else% >=2021-06-01
\DeclareRobustCommand\romanshape[1]{%
\expandafter\def\expandafter\delayed@f@adjustment\expandafter
{\delayed@f@adjustment\delayed@merge@font@shape{#1}}}
@@ -956,9 +790,6 @@
\romanshapeforce{#1}%
\expandafter\def\expandafter\delayed@k@adjustment\expandafter
{\delayed@k@adjustment\set@safe@kanji@shape{#1}{}}}
-\fi
-\ifnum\ltj@@latex@plv>1499
-%%%% LaTeX >= 2021-06-01
\DeclareRobustCommand\usekanji[4]{%
\kanjiencoding{#1}\edef\k@family{#2}%
\set@target@series@kanji{#3}\edef\k@shape{#4}%
@@ -969,42 +800,6 @@
\set@target@series{#3}\edef\f@shape{#4}%
\let\delayed@f@adjustment\@empty
\selectfont\ignorespaces}
-\else\ifnum\ltj@@latex@plv>1000
-%%%% 2021-10-01 PL3 <= LaTeX < 2021-06-01
-\DeclareRobustCommand\usekanji[4]{%
- \kanjiencoding{#1}\edef\k@family{#2}%
- \set@target@series@kanji{#3}\edef\k@shape{#4}%
- \selectfont\ignorespaces}
-\DeclareRobustCommand\useroman[4]{%
- \romanencoding{#1}\edef\f@family{#2}%
- \set@target@series{#3}\edef\f@shape{#4}%
- \selectfont\ignorespaces}
-\else
-%%%% 2020-10-01 <= LaTeX < 2020-10-01 PL3
-\DeclareRobustCommand\usekanji[4]{%
- \kanjiencoding{#1}\edef\k@family{#2}\edef\k@series{#3}\edef\k@shape{#4}%
- \selectfont\ignorespaces}
-\DeclareRobustCommand\useroman[4]{%
- \romanencoding{#1}\edef\f@family{#2}\edef\f@series{#3}\edef\f@shape{#4}%
- \selectfont\ignorespaces}
-\fi\fi
-%%%% LaTeX >= 2020-02-02 END
-\else
-%%%% LaTeX 2019-10-01
-\DeclareRobustCommand\romanseries[1]{\edef\f@series{#1}}
-\DeclareRobustCommand\kanjiseries[1]{\edef\k@series{#1}}
-\DeclareRobustCommand\fontseries[1]{\kanjiseries{#1}\romanseries{#1}}
-\DeclareRobustCommand\romanshape[1]{\edef\f@shape{#1}}
-\DeclareRobustCommand\kanjishape[1]{\edef\k@shape{#1}}
-\DeclareRobustCommand\fontshape[1]{\set@safe@kanji@shape{#1}{}\romanshape{#1}}
-\DeclareRobustCommand\usekanji[4]{%
- \kanjiencoding{#1}\kanjifamily{#2}\kanjiseries{#3}\kanjishape{#4}%
- \selectfont\ignorespaces}
-\DeclareRobustCommand\useroman[4]{%
- \romanencoding{#1}\romanfamily{#2}\romanseries{#3}\romanshape{#4}%
- \selectfont\ignorespaces}
-%%%% LaTeX 2019-10-01 END
-\fi
%%%%
\def\set@safe@kanji@shape#1#2{%
@@ -1026,8 +821,6 @@
\else\useroman{#1}{#2}{#3}{#4}%
\fi}
-\ifnum 0\ifltj@ltfilehook@avail1\fi\ifdefined\@rmfamilyhook1\fi>0
-%%%% LaTeX >= 2020-02-02
\let\prepare@family@series@update@kanji=\prepare@family@series@update
\patchcmd\prepare@family@series@update{\fontfamily}{\romanfamily}{}{}
\patchcmd\prepare@family@series@update@kanji{\if@forced@series}{\if@forced@series@kanji}{}{}
@@ -1049,34 +842,16 @@
\patchcmd\update@series@target@value@kanji{\f@series}{\k@series}{}{}
\def\@meta@family@list@kanji{\@elt{mc}\@elt{gt}\@elt{jtt}}
-\def\@ltj@hook@series@default#1#2#3{%
- \ifltj@ltfilehook@avail % 2020-10-01
- \AddToHook{#1/defaults}{#2}%
- \else\ifcsname @set#1defaultshook\endcsname %after 2020-04-07
- \expandafter\g@addto@macro\csname @set#1defaultshook\endcsname{#2}%
- \else % 2020-02-02
- \expandafter\patchcmd\csname #1 \endcsname{#3}{#3#2}{}{}%
- \fi\fi
-}
-\@ltj@hook@series@default{bfseries}{%
+\AddToHook{bfseries/defaults}{%
\let\bfseries@mc\bfdef@ult
\let\bfseries@gt\bfdef@ult
\let\bfseries@jtt\bfdef@ult
-}{%
- \let\bfseries@rm\bfdef@ult
- \let\bfseries@sf\bfdef@ult
- \let\bfseries@tt\bfdef@ult
}
-\@ltj@hook@series@default{mdseries}{%
+\AddToHook{mdseries/defaults}{%
\let\mdseries@mc\mddef@ult
\let\mdseries@gt\mddef@ult
\let\mdseries@jtt\mddef@ult
-}{%
- \let\mdseries@rm\mddef@ult
- \let\mdseries@sf\mddef@ult
- \let\mdseries@tt\mddef@ult
}
-\let\@ltj@hook@series@default\@undefined
\expandafter\patchcmd\csname bfseries \endcsname{%
\ifx\f@family\rmdef@ult \fontseries\bfseries@rm
@@ -1105,105 +880,41 @@
\fi\fi\fi
}{}{}
-\def\@ltj@hook@series#1#2{%
- \ifltj@ltfilehook@avail % 2020-10-01
- \AddToHook{#1}{#2}%
- \else % 2020-02-02
- \expandafter\patchcmd\csname #1 \endcsname{\selectfont}{#2\selectfont}{}{}%
- \fi
-}
-\@ltj@hook@series{bfseries}{%
+\AddToHook{bfseries}{%
\ifx\k@family\mcdef@ult \kanjiseries\bfseries@mc
\else\ifx\k@family\gtdef@ult \kanjiseries\bfseries@gt
\else\ifx\k@family\jttdef@ult\kanjiseries\bfseries@jtt
\else \kanjiseries\bfdefault
\fi\fi\fi
}
-\@ltj@hook@series{mdseries}{%
+\AddToHook{mdseries}{%
\ifx\k@family\mcdef@ult \kanjiseries\mdseries@mc
\else\ifx\k@family\gtdef@ult \kanjiseries\mdseries@gt
\else\ifx\k@family\jttdef@ult\kanjiseries\mdseries@jtt
\else \kanjiseries\mddefault
\fi\fi\fi
}
-\let\@ltj@hook@series\@undefined
-\def\@ltj@hook@efd#1#2{%
- \ifltj@ltfilehook@avail % 2020-10-01
- \AddToHook{expand@font@defaults}{#1}%
- \else\ifdefined\@expandfontdefaultshook %after 2020-04-07
- \g@addto@macro\@expandfontdefaultshook{#1#2}%
- \else % 2020-02-02
- \appto\expand@font@defaults{#1#2}%
- \fi\fi
-}
-\@ltj@hook@efd{%
+\AddToHook{expand@font@defaults}{%
\edef\mcdef@ult{\mcdefault}%
\edef\gtdef@ult{\gtdefault}%
\edef\jttdef@ult{\jttdefault}%
-}{\edef\kanjidef@ult{\kanjifamilydefault}}
-\let\@ltj@hook@efd\@undefined
+ \edef\kanjidef@ult{\kanjifamilydefault}}
-\ifltj@ltfilehook@avail % 2020-10-01
- \appto\init@series@setup{%
- \ifx\kanjiseriesdefault\kanjiseriesdefault@kernel
- \mdseries
- \let\kanjiseriesdefault\k@series
- \fi
- }
-\else
- \appto\init@series@setup{%
- \ifx\kanjidef@ult\mcdef@ult \mcfamily
- \else\ifx\kanjidef@ult\gtdef@ult \gtfamily
- \else\ifx\kanjidef@ult\jttdef@ult \jttfamily
- \fi\fi\fi
- }
-\fi
-
-\def\@ltj@hook@dfh#1{%
- \ifltj@ltfilehook@avail % 2020-10-01
- \AddToHook{normalfont}{#1}%
- \else\ifdefined\@defaultfamilyhook
- \g@addto@macro\@defaultfamilyhook{#1}%
- \else % 2020-02-02
- \expandafter\patchcmd\csname normalfont \endcsname{\selectfont}{#1\selectfont}{}{}%
- \let\reset@font\normalfont
- \fi\fi
+\appto\init@series@setup{%
+ \ifx\kanjiseriesdefault\kanjiseriesdefault@kernel
+ \mdseries
+ \let\kanjiseriesdefault\k@series
+ \fi
}
-\ifnum\ltj@@latex@plv>1499
-\@ltj@hook@dfh{%
+\AddToHook{normalfont}{%
\kanjiencoding{\kanjiencodingdefault}%
\edef\k@family{\kanjifamilydefault}%
\edef\k@series{\kanjiseriesdefault}%
\edef\k@shape{\kanjishapedefault}%
\let\delayed@k@adjustment\empty
}
-\else
-\@ltj@hook@dfh{%
- \kanjiencoding{\kanjiencodingdefault}%
- \edef\k@family{\kanjifamilydefault}%
- \edef\k@series{\kanjiseriesdefault}%
- \edef\k@shape{\kanjishapedefault}%
-}
-\fi
-\let\@ltj@hook@dfh\@undefined
-%%%% LaTeX >= 2020-02-02 END
-\else
-%%%% LaTeX 2019-10-01
-\DeclareRobustCommand\normalfont{%
- \useroman\encodingdefault\familydefault\seriesdefault\shapedefault
- \usekanji\kanjiencodingdefault\kanjifamilydefault\kanjiseriesdefault\kanjishapedefault}
-\let\reset@font\normalfont
-%%%% LaTeX 2019-10-01 END
-\fi
-
-
-
-\ifdefined\prepare@family@series@update@kanji\else
-%%%% LaTeX 2019-10-01
-\def\prepare@family@series@update@kanji#1{\kanjifamily}
-\fi
\DeclareRobustCommand\mcfamily{%
\unless\ifltj@disablejfam\not@math@alphabet\mcfamily\mathmc\fi
diff --git a/Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-array.sty b/Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-array.sty
index 9575dc3c049..fa5fe7b9339 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-array.sty
+++ b/Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-array.sty
@@ -3,7 +3,9 @@
%
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{lltjp-array}[2019-07-18 Patch to array for LuaTeX-ja]
+\ProvidesPackage{lltjp-array}[2024-07-21 Patch to array for LuaTeX-ja]
+
+\@ifpackageloaded{array}{\def\lltjp@array@array@loaded{1}}{\let\lltjp@array@array@loaded\relax}
\RequirePackage{etoolbox,array}
@@ -11,16 +13,23 @@
\ignorespaces\@sharp\unskip
}{%
\ltj@sharp
-}{}{}
+}{}{% >=2024-06-01
+ \def\ltj@sharp{\relax\pltx@next@inhibitglue\ltjfakeboxbdd\ignorespaces\@sharp\textonly@unskip\ltjfakeboxbdd}
+ \patchcmd\insert@column{%
+ \ignorespaces\@sharp\textonly@unskip
+ }{%
+ \ltj@sharp
+ }{}{}
+}
\@ifpackageloaded{lltjext}{}{%
%% remove extra \xkanjiskip (pLaTeX2e 2016/04/17)
-\def\@tabular{%
- \leavevmode \null
- \hbox \bgroup $\col@sep\tabcolsep \let\d@llarbegin\begingroup
- \let\d@llarend\endgroup
- \@tabarray}
-\def\endtabular{\endarray $\egroup\null}
+\ifnum0<0\lltjp@array@array@loaded
+ \patchcmd{\@tabular}{\leavevmode}{\leavevmode\null}{}{}
+ \patchcmd{\@tabular}{\leavevmode\null\null}{\leavevmode\null}{}{}
+ \apptocmd{\endtabular}{\null}{}{}
+ \let\lltjp@array@array@loaded\undefined
+\fi
\expandafter \let \csname endtabular*\endcsname = \endtabular
}
\endinput
diff --git a/Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-footmisc.sty b/Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-footmisc.sty
index edde267d3c7..5ee7d407ce5 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-footmisc.sty
+++ b/Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-footmisc.sty
@@ -3,63 +3,7 @@
%
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{lltjp-footmisc}[2022-02-19 Patch to footmisc for LuaTeX-ja]
+\ProvidesPackage{lltjp-footmisc}[2024-07-22 Patch to footmisc for LuaTeX-ja]
-\@ifpackagelater{footmisc}{2022-02-10}{%% v6.0a or later
- \patchcmd{\@makenormalcolbox}{\vskip -\@outputbox@depth\@textbottom}%
- {\pltx@adjust@wd@outputbox\vskip -\@outputbox@depth\@textbottom}{}{}%
- \let\ltj@next\endinput
-}{\let\ltj@next\relax}
-\ltj@next
-
-% old (v5.5)
-\let \if@tempswa \ifFN@bottom
-\ifFN@para \@tempswatrue \fi
-\if@tempswa
- \ifFN@bottom
- \toks@{\setbox\@outputbox \box\@cclv
- \xdef\@freelist{\@freelist\@midlist}%
- \global\let\@midlist\@empty
- \@combinefloats
- \ifvoid\footins
- \else
- \setbox\@outputbox \vbox\bgroup
- \boxmaxdepth\@maxdepth
- \unvbox\@outputbox
- \vfill\relax
- }
- \the\FN@temptoken
- \toks@\expandafter{\the\toks@\egroup\fi}
- \else
- \toks@{\ifvoid\footins
- \setbox\@outputbox\box\@cclv
- \else
- \setbox\@outputbox \vbox\bgroup
- \boxmaxdepth\@maxdepth
- \unvbox\@cclv
- }
- \the\FN@temptoken
- \toks@\expandafter{\the\toks@
- \egroup
- \fi
- \xdef\@freelist{\@freelist\@midlist}%
- \global\let\@midlist\@empty
- \@combinefloats
- }%
- \fi
- \toks@\expandafter{\the\toks@
- \ifvbox\@kludgeins
- \@makespecialcolbox
- \else
- \setbox\@outputbox \vbox to\@colht{%
- \@texttop \dimen@\dp\@outputbox
- \unvbox\@outputbox
- \pltx@adjust@wd@outputbox
- \vskip -\dimen@\@textbottom
- }%
- \fi
- \global\maxdepth\@maxdepth
- }
- \edef\@makecol{\the\toks@}
-\fi
-\endinput
+\patchcmd{\@makenormalcolbox}{\vskip -\@outputbox@depth\@textbottom}%
+ {\pltx@adjust@wd@outputbox\vskip -\@outputbox@depth\@textbottom}{}{}%
diff --git a/Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-geometry.sty b/Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-geometry.sty
index 67b0f5de7f7..641fa4a34df 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-geometry.sty
+++ b/Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-geometry.sty
@@ -3,7 +3,7 @@
%
\NeedsTeXFormat{LaTeX2e}
-\ProvidesPackage{lltjp-geometry}[2021-10-24 Patch to geometry for LuaTeX-ja with vertical writing mode]
+\ProvidesPackage{lltjp-geometry}[2024-05-16 Patch to geometry for LuaTeX-ja with vertical writing mode]
\RequirePackage{expl3}
\ifdefined\if@ltj@@geometry@tate\expandafter\endinput\fi
\newif\if@ltj@@geometry@tate
@@ -31,15 +31,6 @@
%============================================
\unless\ifdefined\ltj@ExecuteAfterPackage
-\expandafter\newif\csname ifltj@ltfilehook@avail\endcsname
-\@ifl@t@r\fmtversion{2020-10-01}{%
- \@ifl@t@r\fmtversion{2020-10-02}{\ltj@ltfilehook@availtrue}
- {%
- \ifnum\patch@level<0\relax \ifnum\patch@level<-6 \ltj@ltfilehook@availtrue\fi
- \else\ltj@ltfilehook@availtrue\fi
- }%
-}{}
-\ifltj@ltfilehook@avail
%% \ltj@ExecuteBeforePackage <package><code> and \ltj@ExecuteAfterPackage <package><code>
%% no-starred version: do nothing if the <package> is loaded
%% starred version: do <code> right away if the <package> is loaded
@@ -64,11 +55,6 @@
\@ifpackageloaded{#1}{#2}{\@@ltj@ExecuteBeforePackage{#1}{#2}}%
}
}
-\else
- \RequirePackage{filehook}
- \let\ltj@ExecuteAfterPackage=\AtEndOfPackageFile
- \let\ltj@ExecuteBeforePackage=\AtBeginOfPackageFile
-\fi
\fi
%============================================
@@ -89,12 +75,8 @@
\else
\@gobble\iftrue\csname iftdir\endcsname \bool_set_true:N \l_tmpa_bool \fi
\fi
-\ifltj@ltfilehook@avail
- \prop_map_inline:Nn \g__hook_begindocument_code_prop
- { \tl_if_in:nnT {#2} {\tate} {\bool_set_true:N \l_tmpa_bool} }
-\else
- \tl_if_in:NnT \@begindocumenthook {\tate} {\bool_set_true:N \l_tmpa_bool}
-\fi
+\prop_map_inline:Nn \g__hook_begindocument_code_prop
+ { \tl_if_in:nnT {#2} {\tate} {\bool_set_true:N \l_tmpa_bool} }
\bool_if:NT \l_tmpa_bool {
\if@ltj@@geometry@forceoff
\@ltj@@geometry@tatefalse
diff --git a/Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-siunitx.sty b/Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-siunitx.sty
index 9c4526c3fdb..292cbf00bfe 100644
--- a/Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-siunitx.sty
+++ b/Master/texmf-dist/tex/luatex/luatexja/patches/lltjp-siunitx.sty
@@ -1,5 +1,5 @@
%
-% lltjp-siunitx.sty 2022-12-14
+% lltjp-siunitx.sty 2024-06-10
%
\NeedsTeXFormat{LaTeX2e}
@@ -7,7 +7,6 @@
\RequirePackage{siunitx}
\makeatletter
\ExplSyntaxOn
-\cs_if_exist:NTF \siunitx_print_text:n {% siunitx v3.00
\cs_set_protected:Npn \siunitx_print_text:n #1
{
\text
@@ -32,104 +31,26 @@
}
}
\cs_set_eq:NN \ltj_orig__siunitx_table_collect_begin:w \__siunitx_table_collect_begin:w
-\cs_set_protected:Npn \__siunitx_table_collect_begin:w #1 \relax
- { \ltj_orig__siunitx_table_collect_begin:w }
-\RenewDocumentCommand \tablenum { O { } m }
- {
- \mode_leave_vertical:
- \group_begin:
- \keys_set:nn { siunitx } {#1}
- \siunitx_cell_begin:w
- \relax \ignorespaces #2
- \siunitx_cell_end:
- \group_end:
- }
-}% siunitx v3.00 end
-{% siunitx v2.xx
-\cs_generate_variant:Nn \tl_if_in:NnT { coT }
-\cs_new:Nn \__ltj_siunix_patch_inner:n {
- \cs_if_exist:cT { #1_tl } {
- \tl_if_in:coT { #1_tl } { \tex_char:D } {
- \tl_replace_all:cnn { #1_tl } { \tex_char:D } { \ltjalchar }
- }
+\cs_set_protected:Npn \__siunitx_table_collect_begin:w #1 {
+ \token_if_eq_meaning:NNTF #1 \relax
+ {\ltj_orig__siunitx_table_collect_begin:w }
+ {\ltj_orig__siunitx_table_collect_begin:w #1 }
}
-}
-\cs_new:Nn \__ltj_siunix_patch_inner_math:n {
- \__ltj_siunix_patch_inner:n { l__siunitx_#1_math }
- \__ltj_siunix_patch_inner:n { l__siunitx_#1_text }
-}
-\AtBeginDocument {
- \__ltj_siunix_patch_inner:n { c__siunitx_minus }
- \__ltj_siunix_patch_inner:n { c__siunitx_mu }
- \__ltj_siunix_patch_inner_math:n { angstrom }
- \__ltj_siunix_patch_inner_math:n { arcminute }
- \__ltj_siunix_patch_inner_math:n { arcsecond }
- \__ltj_siunix_patch_inner_math:n { ohm }
-}
-
-%%%% new table column: S and s
-\bool_new:N \l__ltj_siunitx_table_collect_relax_bool
-\cs_set_protected:Npn \__siunitx_table_collect_begin_s: {
- \bool_set_false:N \l__ltj_siunitx_table_collect_relax_bool
- \cs_set_eq:NN \__siunitx_table_collect_token:N
- \__siunitx_table_collect_token_s:N
- \cs_set_eq:NN \__siunitx_table_print: \__siunitx_table_print_s:
- \__siunitx_table_collect_init_s:
- \__siunitx_table_collect_get:
-}
-
-\cs_set_protected:Npn \__siunitx_table_collect_not_braced:N #1
+\cs_set_protected:Npn \__siunitx_table_collect_token:N #1
{
- \token_if_eq_meaning:NNTF #1 \tex_relax:D {
- \bool_if:NTF \l__ltj_siunitx_table_collect_relax_bool {
- \__siunitx_table_collect_not_braced_aux_i:N #1
- } {
- \bool_set_true:N \l__ltj_siunitx_table_collect_relax_bool
- }
- } {
- \token_if_eq_meaning:NNF #1 \ltjfakeboxbdd {
- \token_if_eq_meaning:NNF #1 \pltx@next@inhibitglue {
- \token_if_eq_meaning:NNF #1 \tex_ignorespaces:D
+ \__siunitx_table_collect_search:NnF #1
{
- \token_if_eq_meaning:NNF #1 \tex_unskip:D
- { \__siunitx_table_collect_not_braced_aux_i:N #1 }
+ \ignorespaces { \__siunitx_table_collect_ignore_spaces:N #1}
+ \pltx@next@inhibitglue { \__siunitx_table_collect_loop:}
+ \ltjfakeboxbdd { \__siunitx_table_collect_loop:}
+ \textonly@unskip { \__siunitx_table_collect_loop:}
+ \unskip { \__siunitx_table_collect_loop:}
+ \end { \tabularnewline \end }
+ \relax { \__siunitx_table_collect_relax:N #1 }
+ \tabularnewline { \tabularnewline }
+ \siunitx_cell_end: { \siunitx_cell_end:}
}
- }}}
- \__siunitx_table_collect_next:
- }
-
-\AtBeginDocument
- {
- \@ifpackageloaded { mdwtab }
- {
- \cs_set_protected:Npn \__siunitx_table_collect_not_braced:N #1
- {
- \token_if_eq_meaning:NNTF #1 \tex_relax:D {
- \bool_if:NTF \l__ltj_siunitx_table_collect_relax_bool {
- \__siunitx_table_collect_not_braced_aux_i:N #1
- } {
- \bool_set_true:N \l__ltj_siunitx_table_collect_relax_bool
- }
- } {
- \token_if_eq_meaning:NNF #1 \ltjfakeboxbdd {
- \token_if_eq_meaning:NNF #1 \pltx@next@inhibitglue {
- \token_if_eq_meaning:NNF #1 \tex_ignorespaces:D
- {
- \token_if_eq_meaning:NNF #1 \tex_unskip:D
- {
- \token_if_eq_meaning:NNF #1 \tab@setcr
- {
- \token_if_eq_meaning:NNF #1 \@maybe@unskip
- { \__siunitx_table_collect_not_braced_aux_i:N #1 }
- }
- }
- }
- }}}
- \__siunitx_table_collect_next:
- }
- }
- { }
- }
+ { \__siunitx_table_collect_token_aux:N #1 }
}
\ExplSyntaxOff
\endinput
diff --git a/Master/texmf-dist/tex/luatex/luaxml/luaxml-cssquery.lua b/Master/texmf-dist/tex/luatex/luaxml/luaxml-cssquery.lua
index ebb29abb15c..452656845c4 100644
--- a/Master/texmf-dist/tex/luatex/luaxml/luaxml-cssquery.lua
+++ b/Master/texmf-dist/tex/luatex/luaxml/luaxml-cssquery.lua
@@ -156,7 +156,7 @@ local function cssquery()
-- make sure we deal with a string
value = tostring(value)
-- make the search string safe for pattern matching
- local escaped_search = search:gsub("([%(%)%.%%%+%–%*%?%[%^%$])", "%%%1")
+ local escaped_search = search:gsub("([%(%)%.%%%+%-%#%*%?%[%^%$])", "%%%1")
if modifier == "" then
return value == search
elseif modifier == "|" then
@@ -434,6 +434,18 @@ local function cssquery()
return querylist
end
+ --- Remove selector from the CSS list object.
+ -- All actions that literaly match the given selector will be removed.
+ function CssQuery:remove_selector(
+ selector -- CSS selector to be removed
+ )
+ for pos, obj in ipairs(self.querylist) do
+ if obj.source == selector then
+ table.remove(self.querylist, pos)
+ end
+ end
+ end
+
--- It tests list of queries agaings a DOM element and executes the
--- coresponding function that is saved for the matched query.
-- @return nothing
diff --git a/Master/texmf-dist/tex/luatex/luaxml/luaxml-domobject.lua b/Master/texmf-dist/tex/luatex/luaxml/luaxml-domobject.lua
index 73689add5a1..dca38df0db5 100644
--- a/Master/texmf-dist/tex/luatex/luaxml/luaxml-domobject.lua
+++ b/Master/texmf-dist/tex/luatex/luaxml/luaxml-domobject.lua
@@ -6,16 +6,20 @@ local dom = {}
local xml
local handler
local css_query
+local html
if kpse then
xml = require("luaxml-mod-xml")
handler = require("luaxml-mod-handler")
css_query = require("luaxml-cssquery")
+ html = require("luaxml-mod-html")
else
xml = require("luaxml.mod-xml")
handler = require("luaxml.mod-handler")
css_query = require("luaxml.cssquery")
+ html = require("luaxml.mod-html")
end
+local HtmlParser = html.HtmlParser
local void = {area = true, base = true, br = true, col = true, hr = true, img = true, input = true, link = true, meta = true, param = true}
@@ -91,9 +95,14 @@ local function serialize_dom(parser, current,level, output)
local format = get_action(typ, "start")
insert(format, el, prepare_attributes(attr))
end
- local function text(typ, text)
+ local function text(typ, text, parent)
+ local parent = parent or {}
local format = get_action(typ, "text")
- insert(format, escape_element(text))
+ if parent.verbatim then
+ insert(format, text)
+ else
+ insert(format, escape_element(text))
+ end
end
local function stop(typ, el)
local format = get_action(typ, "stop")
@@ -141,7 +150,7 @@ local function serialize_dom(parser, current,level, output)
end
start(xtype, name, attributes)
- text(xtype,text_content)
+ text(xtype,text_content, (current or {})._parent)
local children = root._children or {}
for _, child in ipairs(children) do
output = serialize_dom(parser,child, level + 1, output)
@@ -411,8 +420,8 @@ local parse = function(
return strings
end
- --- Get table with the inner text of an element -- leading and trailing spaces are removed and elements that contain only white space are ignored.
- --- @return table
+ --- Get table with the inner text of an element - leading and trailing spaces are removed and elements that contain only white space are ignored.
+ -- @return table
function DOM_Object:stripped_strings(
current --- [optional] element to be selected
)
@@ -612,11 +621,83 @@ local parse = function(
-- include the methods to all xml nodes
save_methods(parser._handler.root)
-- parser:
- return parser
+ return parser, DOM_Object
+end
+
+-- table of elements that should be kept without XML escaping in the DOM serialization
+local verbatim_elements = {script=true, style=true}
+
+local function html_to_dom(html_object)
+ -- convert parsed HTML DOM to the XML DOM
+ local dom, DOM_Object = parse("") -- use empty text to just initialize the DOM object
+ -- use root of the DOM object as the original parent
+ local current_parent = dom._handler.root
+
+ local function create_node(tbl)
+ -- create node suitable for LuaXML DOM object
+ tbl._children = {}
+ -- this should copy methods from the DOM object to the newly created object
+ tbl.__index = DOM_Object
+ return setmetatable(tbl, DOM_Object)
+ end
+
+ local function build_tree(object)
+ -- convert tree produced by the HTML parser to LuaXML DOM
+ local typ = object._type
+ -- process particular node types from the HTML parser
+ if typ == "doctype" then
+ current_parent:add_child_node(create_node {_name=object.name, _type="DTD"})
+ elseif typ == "comment" then
+ current_parent:add_child_node(create_node {_text=object.text, _type="COMMENT"})
+ elseif typ == "element" then
+ local attributes = {}
+ -- convert attributes to the form expected by the DOM object
+ for _, attr in ipairs(object.attr) do
+ attributes[attr.name] = attr.value
+ end
+ local element = current_parent:create_element(object.tag, attributes)
+ -- disable escaping of text in dom:serialize() for <script> or <style> elements
+ if verbatim_elements[string.lower(object.tag)] then element.verbatim = true end
+ current_parent:add_child_node(element)
+ -- set the current element as parent for the processing of children
+ local old_parent = current_parent
+ current_parent = element
+ -- process children
+ for k,v in ipairs(object.children) do
+ build_tree(v)
+ end
+ -- restore original parent
+ current_parent = old_parent
+ elseif typ == "text" then
+ local text = current_parent:create_text_node(object.text)
+ current_parent:add_child_node(text)
+ else
+ -- for other node types, just process the children
+ for k,v in ipairs(object.children) do
+ build_tree(v)
+ end
+ end
+
+ end
+ build_tree(html_object)
+ return dom
+end
+
+--- Parse HTML text as a DOM object.
+-- It supports all methods as the object returned by the parse() function.
+-- @param html_str string with the HTML code to be parsed
+-- @return DOM_Object
+local function html_parse(html_str)
+ local html_obj = HtmlParser:init(html_str)
+ local html_dom = html_obj:parse()
+ return html_to_dom(html_dom)
end
+
+
--- @export
return {
parse = parse,
- serialize_dom= serialize_dom
+ serialize_dom= serialize_dom,
+ html_parse = html_parse
}
diff --git a/Master/texmf-dist/tex/luatex/luaxml/luaxml-encodings.lua b/Master/texmf-dist/tex/luatex/luaxml/luaxml-encodings.lua
new file mode 100644
index 00000000000..71bfc81dd1b
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luaxml/luaxml-encodings.lua
@@ -0,0 +1,88 @@
+--- Convert 8-bit encodings to UTF-8
+--- @module luaxml-encodings
+-- this table is generated automatically by this command:
+-- texlua encodings/make_encodings.lua
+local encodings = {
+ ['ibm866'] = 'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀рстуфхцчшщъыьэюяЁёЄєЇїЎў°∙·√№¤■ ',
+ ['iso-8859-5'] = '�������������������������������� ЁЂЃЄЅІЇЈЉЊЋЌ­ЎЏАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя№ёђѓєѕіїјљњћќ§ўџ',
+ ['macintosh'] = 'ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄€‹›fifl‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ',
+ ['windows-1251'] = 'ЂЃ‚ѓ„…†‡€‰Љ‹ЊЌЋЏђ‘’“”•–—�™љ›њќћџ ЎўЈ¤Ґ¦§Ё©Є«¬­®Ї°±Ііґµ¶·ё№є»јЅѕїАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыьэюя',
+ ['iso-8859-13'] = '�������������������������������� ”¢£¤„¦§Ø©Ŗ«¬­®Æ°±²³“µ¶·ø¹ŗ»¼½¾æĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽßąįāćäåęēčéźėģķīļšńņóōõö÷ųłśūüżž’',
+ ['iso-8859-6'] = '�������������������������������� ���¤�������،­�������������؛���؟�ءآأؤإئابةتثجحخدذرزسشصضطظعغ�����ـفقكلمنهوىيًٌٍَُِّْ',
+ ['iso-8859-8'] = '�������������������������������� �¢£¤¥¦§¨©×«¬­®¯°±²³´µ¶·¸¹÷»¼½¾��������������������������������‗אבגדהוזחטיךכלםמןנסעףפץצקרשת��‎‏',
+ ['iso-8859-4'] = '�������������������������������� ĄĸŖ¤ĨĻ§¨ŠĒĢŦ­Ž¯°ą˛ŗ´ĩļˇ¸šēģŧŊžŋĀÁÂÃÄÅÆĮČÉĘËĖÍÎĪĐŅŌĶÔÕÖ×ØŲÚÛÜŨŪßāáâãäåæįčéęëėíîīđņōķôõö÷øųúûüũū˙',
+ ['koi8-r'] = '─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓⌠■∙√≈≤≥ ⌡°²·÷═║╒ё╓╔╕╖╗╘╙╚╛╜╝╞╟╠╡Ё╢╣╤╥╦╧╨╩╪╫╬©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ',
+ ['iso-8859-7'] = '�������������������������������� ‘’£€₯¦§¨©ͺ«¬­�―°±²³΄΅Ά·ΈΉΊ»Ό½ΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡ�ΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ',
+ ['iso-8859-3'] = '�������������������������������� Ħ˘£¤�Ĥ§¨İŞĞĴ­�Ż°ħ²³´µĥ·¸ışğĵ½�żÀÁÂ�ÄĊĈÇÈÉÊËÌÍÎÏ�ÑÒÓÔĠÖ×ĜÙÚÛÜŬŜßàáâ�äċĉçèéêëìíîï�ñòóôġö÷ĝùúûüŭŝ˙',
+ ['windows-1256'] = '€پ‚ƒ„…†‡ˆ‰ٹ‹Œچژڈگ‘’“”•–—ک™ڑ›œ‌‍ں ،¢£¤¥¦§¨©ھ«¬­®¯°±²³´µ¶·¸¹؛»¼½¾؟ہءآأؤإئابةتثجحخدذرزسشصض×طظعغـفقكàلâمنهوçèéêëىيîïًٌٍَôُِ÷ّùْûü‎‏ے',
+ ['windows-1258'] = '€�‚ƒ„…†‡ˆ‰�‹Œ����‘’“”•–—˜™�›œ��Ÿ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂĂÄÅÆÇÈÉÊË̀ÍÎÏĐÑ̉ÓÔƠÖ×ØÙÚÛÜỮßàáâăäåæçèéêë́íîïđṇ̃óôơö÷øùúûüư₫ÿ',
+ ['iso-8859-14'] = '�������������������������������� Ḃḃ£ĊċḊ§Ẁ©ẂḋỲ­®ŸḞḟĠġṀṁ¶ṖẁṗẃṠỳẄẅṡÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏŴÑÒÓÔÕÖṪØÙÚÛÜÝŶßàáâãäåæçèéêëìíîïŵñòóôõöṫøùúûüýŷÿ',
+ ['windows-1252'] = '€�‚ƒ„…†‡ˆ‰Š‹Œ�Ž��‘’“”•–—˜™š›œ�žŸ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ',
+ ['iso-8859-15'] = '�������������������������������� ¡¢£€¥Š§š©ª«¬­®¯°±²³Žµ¶·ž¹º»ŒœŸ¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ',
+ ['x-mac-cyrillic'] = 'АБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯ†°Ґ£§•¶І®©™Ђђ≠Ѓѓ∞±≤≥іµґЈЄєЇїЉљЊњјЅ¬√ƒ≈∆«»… ЋћЌќѕ–—“”‘’÷„ЎўЏџ№Ёёяабвгдежзийклмнопрстуфхцчшщъыьэю€',
+ ['windows-1254'] = '€�‚ƒ„…†‡ˆ‰Š‹Œ����‘’“”•–—˜™š›œ��Ÿ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏĞÑÒÓÔÕÖ×ØÙÚÛÜİŞßàáâãäåæçèéêëìíîïğñòóôõö÷øùúûüışÿ',
+ ['windows-1255'] = '€�‚ƒ„…†‡ˆ‰�‹�����‘’“”•–—˜™�›���� ¡¢£₪¥¦§¨©×«¬­®¯°±²³´µ¶·¸¹÷»¼½¾¿ְֱֲֳִֵֶַָֹֺֻּֽ־ֿ׀ׁׂ׃װױײ׳״�������אבגדהוזחטיךכלםמןנסעףפץצקרשת��‎‏',
+ ['windows-1250'] = '€�‚�„…†‡�‰Š‹ŚŤŽŹ�‘’“”•–—�™š›śťžź ˇ˘Ł¤Ą¦§¨©Ş«¬­®Ż°±˛ł´µ¶·¸ąş»Ľ˝ľżŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüýţ˙',
+ ['koi8-u'] = '─│┌┐└┘├┤┬┴┼▀▄█▌▐░▒▓⌠■∙√≈≤≥ ⌡°²·÷═║╒ёє╔ії╗╘╙╚╛ґў╞╟╠╡ЁЄ╣ІЇ╦╧╨╩╪ҐЎ©юабцдефгхийклмнопярстужвьызшэщчъЮАБЦДЕФГХИЙКЛМНОПЯРСТУЖВЬЫЗШЭЩЧЪ',
+ ['iso-8859-10'] = '�������������������������������� ĄĒĢĪĨĶ§ĻĐŠŦŽ­ŪŊ°ąēģīĩķ·ļđšŧž―ūŋĀÁÂÃÄÅÆĮČÉĘËĖÍÎÏÐŅŌÓÔÕÖŨØŲÚÛÜÝÞßāáâãäåæįčéęëėíîïðņōóôõöũøųúûüýþĸ',
+ ['windows-1257'] = '€�‚�„…†‡�‰�‹�¨ˇ¸�‘’“”•–—�™�›�¯˛� �¢£¤�¦§Ø©Ŗ«¬­®Æ°±²³´µ¶·ø¹ŗ»¼½¾æĄĮĀĆÄÅĘĒČÉŹĖĢĶĪĻŠŃŅÓŌÕÖ×ŲŁŚŪÜŻŽßąįāćäåęēčéźėģķīļšńņóōõö÷ųłśūüżž˙',
+ ['windows-1253'] = '€�‚ƒ„…†‡�‰�‹�����‘’“”•–—�™�›���� ΅Ά£¤¥¦§¨©�«¬­®―°±²³΄µ¶·ΈΉΊ»Ό½ΎΏΐΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡ�ΣΤΥΦΧΨΩΪΫάέήίΰαβγδεζηθικλμνξοπρςστυφχψωϊϋόύώ',
+ ['iso-8859-2'] = '�������������������������������� Ą˘Ł¤ĽŚ§¨ŠŞŤŹ­ŽŻ°ą˛ł´ľśˇ¸šşťź˝žżŔÁÂĂÄĹĆÇČÉĘËĚÍÎĎĐŃŇÓÔŐÖ×ŘŮÚŰÜÝŢßŕáâăäĺćçčéęëěíîďđńňóôőö÷řůúűüýţ˙',
+ ['windows-874'] = '€����…�����������‘’“”•–—�������� กขฃคฅฆงจฉชซฌญฎฏฐฑฒณดตถทธนบปผฝพฟภมยรฤลฦวศษสหฬอฮฯะัาำิีึืฺุู����฿เแโใไๅๆ็่้๊๋์ํ๎๏๐๑๒๓๔๕๖๗๘๙๚๛',
+ ['iso-8859-16'] = '�������������������������������� ĄąŁ€„Š§š©Ș«Ź­źŻ°±ČłŽ”¶·žčș»ŒœŸżÀÁÂĂÄĆÆÇÈÉÊËÌÍÎÏĐŃÒÓÔŐÖŚŰÙÚÛÜĘȚßàáâăäćæçèéêëìíîïđńòóôőöśűùúûüęțÿ',
+}
+
+
+local utfchar = utf8.char
+
+--- Try to find an encoding in HTML string
+---@param str string HTML document
+---@param len number count of characters from the start of the string where it should search for the encoding metadata
+---@return string encoding identifier, or nil and message if no encoding was found
+local function find_html_encoding(str, len)
+ -- try to find encoding in the html document
+ -- we limit search length, because encoding should be in the document head, ideally near the start
+ local len = len or 4096
+ local sub = str:sub(1, len)
+ for meta in sub:gmatch("<meta (.-)>") do
+ local charset = meta:match("charset%s*=%s*[\"']?(.-)[\"']")
+ if charset then return string.lower(charset) end
+ end
+ return nil, "Cannot find the document encoding"
+end
+
+local function load_mapping(enc_name)
+ local enc_name = enc_name or ""
+ local enc = encodings[enc_name]
+ if not enc then return nil, "Cannot load encoding " .. enc_name end
+ local mapping,i = {}, 128
+ for pos, codepoint in utf8.codes(enc) do
+ mapping[i] = utfchar(codepoint)
+ i = i + 1
+ end
+ return mapping
+end
+
+--- Convert string to utf-8
+---@param text string for converting
+---@param mapping table
+---@return string converted string
+local function recode(text, mapping)
+ return text:gsub("(.)", function(char)
+ local charpoint = string.byte(char)
+ if charpoint > 127 then
+ return mapping[charpoint]
+ else
+ return false
+ end
+ end)
+end
+
+
+return {
+ encodings = encodings,
+ find_html_encoding = find_html_encoding,
+ load_mapping = load_mapping,
+ recode = recode
+}
+
diff --git a/Master/texmf-dist/tex/luatex/luaxml/luaxml-mod-html.lua b/Master/texmf-dist/tex/luatex/luaxml/luaxml-mod-html.lua
index 69e32b16e22..d8c2b7e9327 100644
--- a/Master/texmf-dist/tex/luatex/luaxml/luaxml-mod-html.lua
+++ b/Master/texmf-dist/tex/luatex/luaxml/luaxml-mod-html.lua
@@ -1,3 +1,6 @@
+--- HTML parsing module for LuaXML
+-- @module luaxml-mod-html
+-- @author Michal Hoftich <michal.h21@gmail.com
-- Copyright Michal Hoftich, 2022
-- HTML parser inspired by https://browser.engineering/html.html
-- but then redone using https://html.spec.whatwg.org/multipage/parsing.html
@@ -1540,9 +1543,14 @@ local function is_formatting_element(name)
return formatting_element_names[name]
end
-local special_elements = {}
+local function hash_from_array(tbl)
+ local t = {}
+ for _, v in ipairs(tbl) do t[v] = true end
+ return t
+end
+
-local special_elements_list = {"address", "applet", "area", "article", "aside",
+local special_elements_list = hash_from_array {"address", "applet", "area", "article", "aside",
"base", "basefont", "bgsound", "blockquote", "body", "br", "button", "caption",
"center", "col", "colgroup", "dd", "details", "dir", "div", "dl", "dt",
"embed", "fieldset", "figcaption", "figure", "footer", "form", "frame",
@@ -1555,13 +1563,9 @@ local special_elements_list = {"address", "applet", "area", "article", "aside",
"mi","mo","mn","ms","mtext", "annotation-xml","foreignObject","desc", "title"
}
-for k,v in ipairs(special_elements_list) do
- special_elements[v] = true
-end
-
local function is_special(name)
- return special_elements[name]
+ return special_elements_list[name]
end
-- these lists are used in HtmlParser:generate_implied_endtags()
@@ -1649,8 +1653,12 @@ local HtmlTreeStates = {}
+--- @type HtmlParser
local HtmlParser = {}
+--- Initialize the HTML Object
+---@param body string HTML to be parsed
+---@return table initialized object
function HtmlParser:init(body)
local o ={}
setmetatable(o, self)
@@ -1686,10 +1694,11 @@ for _,v in ipairs(self_closing_tags_list) do self_closing_tags[v] = true end
-
+--- Execute the HTML parser
+--- @return table Root node of the HTML DOM
function HtmlParser:parse()
-- we assume utf8 input, you must convert it yourself if the source is
- -- in a different encoding
+ -- in a different encoding. for example using luaxml-encodings library
self.text = {}
self.state = self.default_state
-- this should enable us to pass over some characters that we want to ignore
@@ -1791,6 +1800,7 @@ function HtmlParser:emit(token)
elseif token_type == "start_tag" then
self:add_text()
-- self:start_attribute()
+ self:reset_insertion_mode()
self:start_tag()
-- print("Emit start tag", table.concat(token.name))
-- save last attribute
@@ -1882,8 +1892,139 @@ function HtmlParser:set_xmlns(node, parent)
end
end
+function HtmlParser:pop_element()
+ -- close the current element and add it to the DOM
+ local el = self:close_element()
+ local parent = self:get_parent()
+ parent:add_child(el)
+ return el
+end
+
+local close_p_at_start = hash_from_array {"address", "article", "aside", "blockquote", "center", "details", "dialog", "dir", "div", "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "main", "menu", "nav", "ol", "p", "search", "section", "summary", "ul", "pre", "listing", "form", "table", "xmp", "hr"}
+
+local close_headers = hash_from_array {"h1", "h2", "h3", "h4", "h5", "h6"}
+
+local body_modes = hash_from_array {"in_body", "in_cell", "in_row", "in_select", "in_table", "in_table_body", "in_frameset"}
+
+local list_items = hash_from_array {"li", "dt", "dd"}
+
+local close_address_at_end = hash_from_array{"address", "article", "aside", "blockquote", "button", "center", "details", "dialog", "dir", "div", "dl", "fieldset", "figcaption", "figure", "footer", "header", "hgroup", "listing", "main", "menu", "nav", "ol", "pre", "search", "section", "summary", "ul", "form"}
+
+
+function HtmlParser:close_unfinished(name)
+ -- close all unfinished elements until the element with the given name is found
+ for i = #self.unfinished, 1, -1 do
+ local el = self:pop_element()
+ if el.tag == name then
+ break
+ end
+ end
+end
+
+
+function HtmlParser:close_paragraph()
+ -- close currently open <p> elements
+ self:close_unfinished("p")
+end
+
+function HtmlParser:current_element_name()
+ -- return name of the current element
+ return self:get_parent().tag
+end
+
+local not_specials = hash_from_array { "address", "div", "p"}
+
+local function handle_list_item(self, name)
+ -- we handle li, dt and dd. dt and dd should close each other, li closes only itself
+ local names = {dt = true, dd = true}
+ if name == "li" then names = {li=true} end
+ for i = #self.unfinished, 1, -1 do
+ local current = self.unfinished[i]
+ local current_tag = current.tag
+ if names[current_tag] then
+ self:generate_implied_endtags(nil, {current.tag})
+ for j = #self.unfinished, i, -1 do
+ self:pop_element()
+ end
+ break
+ elseif is_special(current_tag) and not not_specials[name] then
+ break
+ end
+ end
+end
+
+local close_paragraph = function(self)
+ if is_in_button_scope(self, "p") then
+ self:close_paragraph()
+ end
+end
+
+function HtmlParser:handle_insertion_mode(token)
+ -- simple handling of https://html.spec.whatwg.org/multipage/parsing.html#tree-construction
+ -- we don't support most rules, just the most important for avoiding mismatched tags
+
+ if body_modes[self.insertion_mode] then
+ if token.type == "start_tag" then
+ local name = table.concat(token.name)
+ if close_p_at_start[name] then close_paragraph(self) end
+ if close_headers[name] then
+ close_paragraph(self)
+ -- close current element if it is already header
+ if close_headers[self:current_element_name()] then
+ self:pop_element()
+ end
+ elseif name == "pre" or name == "listing" then
+ -- we should ignore next "\n" char token
+ elseif name == "image" then
+ -- image tag is an error, change to <img>
+ token.name = {"img"}
+ elseif list_items[name] then
+ handle_list_item(self, name)
+ close_paragraph(self)
+ end
+ elseif token.type == "end_tag" then
+ local name = table.concat(token.name)
+ if close_address_at_end[name] then
+ if is_in_scope(self, name, {}) then
+ self:close_unfinished(name)
+ else
+ token.type = "ignore"
+ end
+ elseif name == "p" then
+ if not is_in_button_scope(self, "p") then
+ local parent = self:get_parent()
+ local node = Element:init("p", parent)
+ table.insert(self.unfinished, node)
+ end
+ -- use self:close_paragraph() instead of close_paragraph() because we don't need to check scope at this point
+ self:close_paragraph()
+ elseif name == "br" then
+ token.type = "start_tag"
+ elseif close_headers[name] then
+ local header_in_scope = false
+ -- detect, if there are any open h1-h6 tag and close it
+ for el, _ in pairs(close_headers) do
+ if is_in_scope(self, el, {}) then
+ header_in_scope = el
+ break
+ end
+ end
+ if not header_in_scope then
+ token.type = "ignore"
+ else
+ self:close_unfinished(header_in_scope)
+ end
+ end
+ end
+ end
+end
+
+local rawtext_elements = hash_from_array {"style", "textarea", "xmp"}
+
+
function HtmlParser:start_tag()
local token = self.current_token
+ self:handle_insertion_mode(token)
if token.type == "start_tag" then
-- close all currently opened attributes
self:start_attribute()
@@ -1894,18 +2035,18 @@ function HtmlParser:start_tag()
node.attr = token.attr
node.self_closing = token.self_closing
self:set_xmlns(node)
- --
+ -- in this handler we should close <p> or <li> elements without explicit closing tags
if token.self_closing -- <img />
or self_closing_tags[name] -- void elements
then
- parent:add_child(node)
+ parent:add_child(node, node.tag)
else
-- add to the unfinished list
table.insert(self.unfinished, node)
end
if name == "title" then
self.element_state = "rcdata"
- elseif name == "style" then
+ elseif rawtext_elements[name] then
self.element_state = "rawtext"
elseif name == "script" then
self.element_state = "script_data"
@@ -1916,11 +2057,13 @@ end
function HtmlParser:end_tag()
-- close current opened element
local token = self.current_token
+ self:handle_insertion_mode(token)
if token.type == "end_tag" then
if #self.unfinished==0 then return nil end
- local node = self:close_element()
- local parent = self:get_parent()
- parent:add_child(node)
+ -- close the current element only if the token is in the current scope
+ if is_in_scope(self, table.concat(token.name), {}) then
+ self:pop_element()
+ end
end
end
@@ -1964,6 +2107,21 @@ function HtmlParser:adjusted_current_node()
end
+local simple_modes = {
+ body = "in_body",
+ td = "in_cell",
+ th = "in_cell",
+ tr = "in_row",
+ tbody = "in_table_body",
+ thead = "in_table_body",
+ tfoot = "in_table_body",
+ caption = "in_caption",
+ colgroup = "in_column_group",
+ table = "in_table",
+ template = "current_template_insertion_mode",
+ frameset = "in_frameset"
+}
+
function HtmlParser:reset_insertion_mode()
-- https://html.spec.whatwg.org/multipage/parsing.html#reset-the-insertion-mode-appropriately
local last = false
@@ -1977,16 +2135,33 @@ function HtmlParser:reset_insertion_mode()
if name == "head" and last == true then
self:switch_insertion("in_head")
return
- elseif name == "body" then
- self:switch_insertion("in_body")
- return
elseif name == "html" then
- if self.head_pointer then
+ if not self.head_pointer then
self:switch_insertion("before_head")
return
else
self:switch_insertion("after_head")
+ return
+ end
+ elseif name == "select" then
+ if not last then
+ for x = position -1, 1, -1 do
+ if x == 1 then break end
+ local ancestor = self.unfinished[x]
+ local ancestor_name = ancestor.tag
+ if ancestor_name == "template" then
+ break
+ elseif ancestor_name == "table" then
+ self:switch_insertion("in_select_in_table")
+ return
+ end
+ end
end
+ self:switch_insertion("in_select")
+ return
+ elseif simple_modes[name] then
+ self:switch_insertion(simple_modes[name])
+ return
elseif last == true then
self:switch_insertion("in_body")
return
@@ -2006,8 +2181,8 @@ function HtmlParser:generate_implied_endtags(included, ignored)
local current = self:current_node() or {}
-- keep removing elements while they are in the "included" list
if included[current.tag] then
- table.remove(self.unfinished)
- self:generate_implied_endtags(ignored)
+ self:pop_element()
+ self:generate_implied_endtags(included, ignored)
end
end
@@ -2023,9 +2198,7 @@ function HtmlParser:finish()
self:start_tag("html")
end
while #self.unfinished > 0 do
- local node = self:close_element()
- local parent = self:get_parent()
- parent:add_child(node)
+ self:pop_element()
end
-- return root element
return self.Document -- self:close_element()
diff --git a/Master/texmf-dist/tex/luatex/luaxml/luaxml-namedentities.lua b/Master/texmf-dist/tex/luatex/luaxml/luaxml-namedentities.lua
index 0e6399ab135..5c5ff007770 100644
--- a/Master/texmf-dist/tex/luatex/luaxml/luaxml-namedentities.lua
+++ b/Master/texmf-dist/tex/luatex/luaxml/luaxml-namedentities.lua
@@ -1,2234 +1,2233 @@
-local utf8 = require "utf8"
return {
-["Subset"]="⋐",
-["Chi"]="Χ",
-["tprime"]="‴",
-["lneq"]="⪇",
-["RightUpTeeVector"]="⥜",
-["cscr"]="𝒸",
-["leftrightarrows"]="⇆",
-["LeftRightVector"]="⥎",
-["Laplacetrf"]="ℒ",
-["boxHd"]="╤",
-["GreaterSlantEqual"]="⩾",
-["sqsub"]="⊏",
-["nvdash"]="⊬",
-["boxHu"]="╧",
-["vcy"]="в",
-["DiacriticalDoubleAcute"]="˝",
-["nvHarr"]="⤄",
-["lnapprox"]="⪉",
-["fscr"]="𝒻",
-["OverBracket"]="⎴",
-["pm"]="±",
-["ovbar"]="⌽",
-["larrhk"]="↩",
-["atilde"]="ã",
-["Igrave"]="Ì",
-["profsurf"]="⌓",
-["Sigma"]="Σ",
-["rHar"]="⥤",
-["Gcedil"]="Ģ",
-["sect"]="§",
-["nmid"]="∤",
-["escr"]="ℯ",
-["delta"]="δ",
-["male"]="♂",
-["Integral"]="∫",
-["RightUpVectorBar"]="⥔",
-["alefsym"]="ℵ",
-["nsqsube"]="⋢",
-["Nacute"]="Ń",
-["mcomma"]="⨩",
-["ApplyFunction"]=utf8.char(0x2061),
-["rfisht"]="⥽",
-["phmmat"]="ℳ",
-["rarrw"]="↝",
-["backepsilon"]="϶",
-["hscr"]="𝒽",
-["middot"]="·",
-["ldrushar"]="⥋",
-["supne"]="⊋",
-["Longleftrightarrow"]="⟺",
-["Oacute"]="Ó",
-["af"]="⁡",
+["Implies"]="⇒",
+["longrightarrow"]="⟶",
+["precneqq"]="⪵",
+["geqslant"]="⩾",
+["Product"]="∏",
+["Scirc"]="Ŝ",
+["lvnE"]="≨︀",
+["dotminus"]="∸",
+["sscr"]="𝓈",
+["capdot"]="⩀",
+["dlcrop"]="⌍",
+["omacr"]="ō",
+["sext"]="✶",
+["xutri"]="△",
+["xrArr"]="⟹",
+["glE"]="⪒",
+["NotSupersetEqual"]="⊉",
+["backsim"]="∽",
["sup"]="⊃",
-["lozenge"]="◊",
-["scy"]="с",
-["gscr"]="ℊ",
-["smallsetminus"]="∖",
+["realpart"]="ℜ",
["hardcy"]="ъ",
-["DoubleVerticalBar"]="∥",
-["Yuml"]="Ÿ",
-["plusdu"]="⨥",
-["NotSucceedsSlantEqual"]="⋡",
-["nwnear"]="⤧",
-["lfloor"]="⌊",
-["rcy"]="р",
-["jscr"]="𝒿",
-["AMP"]="&",
-["acute"]="´",
-["uacute"]="ú",
-["Or"]="⩔",
-["rdldhar"]="⥩",
-["langd"]="⦑",
-["Iacute"]="Í",
-["spar"]="∥",
-["ucy"]="у",
-["rsh"]="↱",
-["Kcedil"]="Ķ",
-["iscr"]="𝒾",
-["lambda"]="λ",
-["lbrkslu"]="⦍",
-["napE"]="⩰̸",
-["shcy"]="ш",
-["nsupE"]="⫆̸",
-["Ycirc"]="Ŷ",
-["sect"]="§",
-["precnapprox"]="⪹",
-["iocy"]="ё",
-["dzcy"]="џ",
+["sqcap"]="⊓",
+["brvbar"]="¦",
+["LT"]="<",
+["udarr"]="⇅",
+["lozf"]="⧫",
+["Eogon"]="Ę",
+["frac18"]="⅛",
+["lesssim"]="≲",
+["wedbar"]="⩟",
+["EmptyVerySmallSquare"]="▫",
+["aring"]="å",
+["lesdoto"]="⪁",
+["ltquest"]="⩻",
+["LeftUpTeeVector"]="⥠",
+["FilledSmallSquare"]="◼",
+["mho"]="℧",
+["NotGreaterTilde"]="≵",
+["xharr"]="⟷",
+["NotSucceedsEqual"]="⪰̸",
+["sqsupset"]="⊐",
+["Ccedil"]="Ç",
+["aacute"]="á",
+["succcurlyeq"]="≽",
+["gneq"]="⪈",
+["forall"]="∀",
+["rightharpoonup"]="⇀",
+["leftarrow"]="←",
+["ang"]="∠",
+["mapstoup"]="↥",
+["xscr"]="𝓍",
+["NotTildeEqual"]="≄",
+["ograve"]="ò",
+["boxdl"]="┐",
+["DownLeftVectorBar"]="⥖",
+["nsup"]="⊅",
+["shchcy"]="щ",
+["demptyv"]="⦱",
+["apos"]="'",
+["between"]="≬",
+["leftrightsquigarrow"]="↭",
+["gtcc"]="⪧",
+["grave"]="`",
+["bigodot"]="⨀",
+["oline"]="‾",
+["angmsdad"]="⦫",
+["NotCongruent"]="≢",
+["gtquest"]="⩼",
+["fltns"]="▱",
+["smeparsl"]="⧤",
+["Eta"]="Η",
+["ltdot"]="⋖",
+["rhard"]="⇁",
+["rscr"]="𝓇",
["ETH"]="Ð",
-["GreaterTilde"]="≳",
-["coprod"]="∐",
-["rpar"]=")",
-["lthree"]="⋋",
-["ImaginaryI"]="ⅈ",
-["DoubleUpDownArrow"]="⇕",
-["intercal"]="⊺",
-["spadesuit"]="♠",
-["boxVH"]="╬",
-["smashp"]="⨳",
-["nu"]="ν",
-["Agrave"]="À",
-["boxtimes"]="⊠",
-["sext"]="✶",
-["nsub"]="⊄",
-["oelig"]="œ",
-["GreaterEqual"]="≥",
-["TRADE"]="™",
-["dtrif"]="▾",
-["nless"]="≮",
-["mu"]="μ",
-["larrsim"]="⥳",
-["GreaterEqualLess"]="⋛",
-["Uuml"]="Ü",
-["LeftArrowBar"]="⇤",
-["ntrianglerighteq"]="⋭",
-["DiacriticalDot"]="˙",
-["LongLeftArrow"]="⟵",
-["agrave"]="à",
-["lmoustache"]="⎰",
-["nvDash"]="⊭",
-["para"]="¶",
-["nlt"]="≮",
-["Eacute"]="É",
-["spades"]="♠",
-["lrcorner"]="⌟",
-["checkmark"]="✓",
-["lessdot"]="⋖",
-["opar"]="⦷",
-["nVDash"]="⊯",
-["pertenk"]="‱",
-["range"]="⦥",
-["Pr"]="⪻",
-["Gammad"]="Ϝ",
-["ape"]="≊",
-["Longleftarrow"]="⟸",
-["boxV"]="║",
-["rightthreetimes"]="⋌",
+["iocy"]="ё",
+["semi"]=";",
+["nexists"]="∄",
+["approxeq"]="≊",
+["compfn"]="∘",
+["sstarf"]="⋆",
+["angrtvbd"]="⦝",
["gnap"]="⪊",
-["vzigzag"]="⦚",
-["Ecirc"]="Ê",
-["npar"]="∦",
-["notinvb"]="⋷",
-["Tau"]="Τ",
-["blank"]="␣",
-["Kappa"]="Κ",
-["rmoust"]="⎱",
-["GJcy"]="Ѓ",
-["ufisht"]="⥾",
-["NotLeftTriangleBar"]="⧏̸",
-["bigvee"]="⋁",
-["lrhar"]="⇋",
-["supset"]="⊃",
-["uwangle"]="⦧",
-["UpTeeArrow"]="↥",
-["supE"]="⫆",
-["imof"]="⊷",
-["leg"]="⋚",
-["notniva"]="∌",
-["nvgt"]=">⃒",
-["rthree"]="⋌",
-["yfr"]="𝔶",
-["uHar"]="⥣",
-["nshortmid"]="∤",
-["biguplus"]="⨄",
-["barvee"]="⊽",
-["iff"]="⇔",
-["boxvH"]="╪",
-["simrarr"]="⥲",
-["Egrave"]="È",
-["ntilde"]="ñ",
-["VerticalTilde"]="≀",
-["sigmaf"]="ς",
-["khcy"]="х",
-["planck"]="ℏ",
-["NotNestedGreaterGreater"]="⪢̸",
-["NonBreakingSpace"]=" ",
-["OpenCurlyQuote"]="‘",
-["supsim"]="⫈",
-["cudarrl"]="⤸",
-["theta"]="θ",
-["notindot"]="⋵̸",
-["Omicron"]="Ο",
-["ccedil"]="ç",
-["colone"]="≔",
-["bscr"]="𝒷",
-["Dagger"]="‡",
-["comma"]=",",
+["mDDot"]="∺",
+["udblac"]="ű",
["Acirc"]="Â",
-["plankv"]="ℏ",
-["boxdr"]="┌",
-["rarrap"]="⥵",
-["rmoustache"]="⎱",
-["LeftAngleBracket"]="⟨",
-["Cacute"]="Ć",
-["blk34"]="▓",
-["rfloor"]="⌋",
-["awconint"]="∳",
-["sfrown"]="⌢",
-["middot"]="·",
-["ascr"]="𝒶",
-["dot"]="˙",
-["caron"]="ˇ",
-["image"]="ℑ",
-["esdot"]="≐",
-["ohbar"]="⦵",
-["rarrb"]="⇥",
-["submult"]="⫁",
-["plusb"]="⊞",
-["oopf"]="𝕠",
-["breve"]="˘",
-["conint"]="∮",
-["angrt"]="∟",
-["nbump"]="≎̸",
-["raquo"]="»",
-["Iuml"]="Ï",
-["Rcedil"]="Ŗ",
-["minus"]="−",
-["nsucceq"]="⪰̸",
-["telrec"]="⌕",
-["CHcy"]="Ч",
-["nrightarrow"]="↛",
-["NotRightTriangle"]="⋫",
-["zfr"]="𝔷",
-["succ"]="≻",
-["Aacute"]="Á",
-["NestedLessLess"]="≪",
-["RightTeeArrow"]="↦",
-["homtht"]="∻",
-["Cup"]="⋓",
-["lcub"]="{",
-["race"]="∽̱",
-["THORN"]="Þ",
-["propto"]="∝",
-["odblac"]="ő",
-["mumap"]="⊸",
-["filig"]="fi",
-["ecir"]="≖",
-["DoubleRightArrow"]="⇒",
-["npreceq"]="⪯̸",
-["female"]="♀",
-["LeftFloor"]="⌊",
-["gtrarr"]="⥸",
-["dotsquare"]="⊡",
-["map"]="↦",
-["OverBrace"]="⏞",
-["zopf"]="𝕫",
-["rang"]="⟩",
-["laquo"]="«",
-["elsdot"]="⪗",
-["frac56"]="⅚",
-["Iuml"]="Ï",
-["ocirc"]="ô",
-["clubs"]="♣",
-["IOcy"]="Ё",
-["scnE"]="⪶",
-["deg"]="°",
-["simgE"]="⪠",
-["nap"]="≉",
-["blacktriangle"]="▴",
-["edot"]="ė",
-["epsiv"]="ϵ",
-["napprox"]="≉",
-["NotGreaterSlantEqual"]="⩾̸",
-["prap"]="⪷",
-["lnap"]="⪉",
-["circledS"]="Ⓢ",
-["lang"]="⟨",
-["qprime"]="⁗",
-["aelig"]="æ",
-["ncongdot"]="⩭̸",
-["supdsub"]="⫘",
-["nltrie"]="⋬",
-["xopf"]="𝕩",
+["UnderParenthesis"]="⏝",
+["nisd"]="⋺",
+["lneq"]="⪇",
+["Dagger"]="‡",
+["qscr"]="𝓆",
+["gneqq"]="≩",
+["doteqdot"]="≑",
+["DoubleVerticalBar"]="∥",
+["emptyset"]="∅",
+["lEg"]="⪋",
+["subseteq"]="⊆",
+["dwangle"]="⦦",
+["dotplus"]="∔",
+["NotPrecedesSlantEqual"]="⋠",
+["bnot"]="⌐",
["LeftDownVector"]="⇃",
-["duarr"]="⇵",
-["urcorner"]="⌝",
-["nvltrie"]="⊴⃒",
-["Pi"]="Π",
+["leg"]="⋚",
+["Therefore"]="∴",
+["Omega"]="Ω",
+["acE"]="∾̳",
+["Auml"]="Ä",
+["xvee"]="⋁",
["Eacute"]="É",
-["nGtv"]="≫̸",
-["icirc"]="î",
-["twoheadleftarrow"]="↞",
+["LeftFloor"]="⌊",
+["swnwar"]="⤪",
+["Jukcy"]="Є",
+["nless"]="≮",
+["NotSquareSupersetEqual"]="⋣",
+["larrfs"]="⤝",
+["gcy"]="г",
+["solbar"]="⌿",
+["rharul"]="⥬",
+["dscy"]="ѕ",
+["yen"]="¥",
+["ForAll"]="∀",
+["DownArrow"]="↓",
+["qprime"]="⁗",
+["NegativeThickSpace"]="​",
+["part"]="∂",
+["Iukcy"]="І",
+["ltcc"]="⪦",
+["xlArr"]="⟸",
+["fcy"]="ф",
+["gl"]="≷",
+["rsh"]="↱",
+["lrhar"]="⇋",
["divide"]="÷",
-["yopf"]="𝕪",
-["ntlg"]="≸",
-["Darr"]="↡",
+["bemptyv"]="⦰",
+["rx"]="℞",
+["ecy"]="э",
+["ApplyFunction"]="⁡",
+["divideontimes"]="⋇",
+["prod"]="∏",
+["boxHU"]="╩",
+["HARDcy"]="Ъ",
+["mstpos"]="∾",
+["llcorner"]="⌞",
+["rsquor"]="’",
+["NotTildeFullEqual"]="≇",
+["mlcp"]="⫛",
+["cemptyv"]="⦲",
+["Proportional"]="∝",
+["DiacriticalDoubleAcute"]="˝",
+["dcy"]="д",
+["Yacute"]="Ý",
+["egsdot"]="⪘",
["hslash"]="ℏ",
-["Coproduct"]="∐",
-["profline"]="⌒",
-["imagline"]="ℐ",
-["chcy"]="ч",
-["ccedil"]="ç",
-["PrecedesEqual"]="⪯",
-["jcirc"]="ĵ",
-["nang"]="∠⃒",
-["Icirc"]="Î",
-["nbumpe"]="≏̸",
-["incare"]="℅",
-["tint"]="∭",
-["nhArr"]="⇎",
-["emsp13"]=" ",
-["blacktriangleleft"]="◂",
-["Star"]="⋆",
-["hkswarow"]="⤦",
-["NegativeThickSpace"]="​",
-["eDot"]="≑",
-["Euml"]="Ë",
-["scaron"]="š",
-["RightDownVectorBar"]="⥕",
-["cent"]="¢",
-["jukcy"]="є",
-["backsimeq"]="⋍",
-["Ncy"]="Н",
-["DD"]="ⅅ",
-["circledast"]="⊛",
-["ccirc"]="ĉ",
-["rsaquo"]="›",
-["YIcy"]="Ї",
-["iquest"]="¿",
-["NotExists"]="∄",
-["iukcy"]="і",
-["Tab"]=" ",
-["Equilibrium"]="⇌",
-["nLt"]="≪⃒",
-["yen"]="¥",
-["CircleDot"]="⊙",
-["CircleMinus"]="⊖",
-["topf"]="𝕥",
-["equivDD"]="⩸",
-["DoubleLeftRightArrow"]="⇔",
-["ngsim"]="≵",
-["upuparrows"]="⇈",
-["ll"]="≪",
-["cirscir"]="⧂",
-["ShortLeftArrow"]="←",
-["angmsdag"]="⦮",
-["shortmid"]="∣",
-["ngeqslant"]="⩾̸",
-["subset"]="⊂",
-["curvearrowleft"]="↶",
-["gdot"]="ġ",
-["circledcirc"]="⊚",
-["Pcy"]="П",
-["asymp"]="≈",
-["boxUr"]="╙",
-["uopf"]="𝕦",
-["frac15"]="⅕",
-["Iacute"]="Í",
-["Utilde"]="Ũ",
-["Congruent"]="≡",
-["nhpar"]="⫲",
-["capbrcup"]="⩉",
-["ordf"]="ª",
-["SOFTcy"]="Ь",
-["nlArr"]="⇍",
-["not"]="¬",
-["ffllig"]="ffl",
-["nprec"]="⊀",
-["Hat"]="^",
+["infin"]="∞",
["Auml"]="Ä",
-["ntriangleleft"]="⋪",
-["longmapsto"]="⟼",
-["nvrtrie"]="⊵⃒",
-["timesb"]="⊠",
-["lsh"]="↰",
-["Jcy"]="Й",
-["gcirc"]="ĝ",
-["Oacute"]="Ó",
-["vartriangleright"]="⊳",
-["NotRightTriangleEqual"]="⋭",
-["Rightarrow"]="⇒",
-["ast"]="*",
-["hamilt"]="ℋ",
-["Ncedil"]="Ņ",
-["apE"]="⩰",
-["macr"]="¯",
-["cwconint"]="∲",
-["Kcy"]="К",
-["Ucirc"]="Û",
-["hcirc"]="ĥ",
-["yacy"]="я",
-["uml"]="¨",
-["popf"]="𝕡",
-["bumpE"]="⪮",
-["varnothing"]="∅",
-["RightUpVector"]="↾",
-["curren"]="¤",
-["Scedil"]="Ş",
-["FilledVerySmallSquare"]="▪",
-["dollar"]="$",
-["Lcy"]="Л",
-["longrightarrow"]="⟶",
-["LeftTee"]="⊣",
-["excl"]="!",
-["acirc"]="â",
-["wp"]="℘",
-["lcaron"]="ľ",
-["NotGreaterFullEqual"]="≧̸",
-["CounterClockwiseContourIntegral"]="∳",
-["sup2"]="²",
-["rnmid"]="⫮",
-["Lcedil"]="Ļ",
-["ddotseq"]="⩷",
-["tbrk"]="⎴",
-["mlcp"]="⫛",
-["rarrhk"]="↪",
-["Tilde"]="∼",
-["Mcy"]="М",
-["aring"]="å",
-["rarrsim"]="⥴",
-["nopf"]="𝕟",
-["aelig"]="æ",
-["order"]="ℴ",
-["diamondsuit"]="♦",
-["nvsim"]="∼⃒",
-["lhard"]="↽",
-["commat"]="@",
-["qint"]="⨌",
-["lsquo"]="‘",
-["sqcaps"]="⊓︀",
-["circlearrowleft"]="↺",
-["NotElement"]="∉",
-["measuredangle"]="∡",
-["Atilde"]="Ã",
-["CapitalDifferentialD"]="ⅅ",
-["kgreen"]="ĸ",
-["Cscr"]="𝒞",
+["Wcirc"]="Ŵ",
+["larrtl"]="↢",
+["Aacute"]="Á",
+["LeftTriangleEqual"]="⊴",
+["NegativeMediumSpace"]="​",
+["TripleDot"]="⃛",
+["utdot"]="⋰",
+["isinv"]="∈",
+["looparrowright"]="↬",
+["loang"]="⟬",
+["multimap"]="⊸",
["NotLessEqual"]="≰",
-["trpezium"]="⏢",
-["ne"]="≠",
-["NotSuperset"]="⊃⃒",
-["nearrow"]="↗",
-["ncong"]="≇",
-["doteqdot"]="≑",
-["supmult"]="⫂",
-["longleftrightarrow"]="⟷",
-["Rarr"]="↠",
-["DoubleUpArrow"]="⇑",
-["Dscr"]="𝒟",
-["mp"]="∓",
-["jmath"]="ȷ",
-["erarr"]="⥱",
-["searrow"]="↘",
-["Sup"]="⋑",
-["lvnE"]="≨︀",
-["ffilig"]="ffi",
-["NotSquareSupersetEqual"]="⋣",
-["bullet"]="•",
-["bigstar"]="★",
-["cylcty"]="⌭",
-["nvle"]="≤⃒",
-["TildeFullEqual"]="≅",
-["lopf"]="𝕝",
-["sqsupseteq"]="⊒",
-["lt"]="<",
-["geqslant"]="⩾",
+["midcir"]="⫰",
+["nge"]="≱",
["quot"]="\"",
-["le"]="≤",
-["square"]="□",
-["sigma"]="σ",
-["prE"]="⪳",
-["rtrie"]="⊵",
-["triangleq"]="≜",
+["REG"]="®",
+["div"]="÷",
+["complexes"]="ℂ",
+["lhblk"]="▄",
+["gvnE"]="≩︀",
+["leftharpoonup"]="↼",
+["it"]="⁢",
+["clubsuit"]="♣",
+["iff"]="⇔",
+["Hacek"]="ˇ",
+["CircleTimes"]="⊗",
+["Cacute"]="Ć",
+["rarrtl"]="↣",
+["RightDownVector"]="⇂",
+["rarrfs"]="⤞",
+["UpArrowBar"]="⤒",
+["male"]="♂",
+["RightTriangle"]="⊳",
+["GreaterTilde"]="≳",
+["Barwed"]="⌆",
+["ltlarr"]="⥶",
+["Zdot"]="Ż",
+["parsim"]="⫳",
+["Ugrave"]="Ù",
+["Dot"]="¨",
+["circleddash"]="⊝",
+["rsaquo"]="›",
+["hyphen"]="‐",
+["angrt"]="∟",
+["RightTriangleEqual"]="⊵",
+["Darr"]="↡",
+["ulcrop"]="⌏",
+["olcir"]="⦾",
+["gimel"]="ℷ",
+["gel"]="⋛",
+["SquareSubset"]="⊏",
+["Uacute"]="Ú",
+["gt"]=">",
+["lnap"]="⪉",
+["Union"]="⋃",
+["nu"]="ν",
+["and"]="∧",
+["ltcir"]="⩹",
["Fscr"]="ℱ",
+["ee"]="ⅇ",
+["laquo"]="«",
+["Hfr"]="ℌ",
+["prec"]="≺",
+["imagline"]="ℐ",
+["precnsim"]="⋨",
+["zhcy"]="ж",
+["mu"]="μ",
+["rlarr"]="⇄",
+["pound"]="£",
+["origof"]="⊶",
+["rfloor"]="⌋",
+["lnsim"]="⋦",
+["nVdash"]="⊮",
+["otimes"]="⊗",
+["iuml"]="ï",
+["Cscr"]="𝒞",
+["lsime"]="⪍",
+["ngeqq"]="≧̸",
+["Del"]="∇",
+["Coproduct"]="∐",
+["NotSubsetEqual"]="⊈",
+["HilbertSpace"]="ℋ",
+["frac58"]="⅝",
+["cap"]="∩",
+["roang"]="⟭",
+["intlarhk"]="⨗",
+["DownTee"]="⊤",
+["thickapprox"]="≈",
+["prnap"]="⪹",
+["laquo"]="«",
+["lesdot"]="⩿",
+["inodot"]="ı",
+["Hscr"]="ℋ",
+["YIcy"]="Ї",
+["ctdot"]="⋯",
+["thetav"]="ϑ",
+["DoubleUpDownArrow"]="⇕",
+["succ"]="≻",
+["nbumpe"]="≏̸",
+["ReverseElement"]="∋",
+["Oacute"]="Ó",
+["equest"]="≟",
+["Lt"]="≪",
+["Nacute"]="Ń",
["DiacriticalTilde"]="˜",
-["SucceedsSlantEqual"]="≽",
-["mopf"]="𝕞",
-["Ecaron"]="Ě",
-["UpArrowDownArrow"]="⇅",
-["ges"]="⩾",
-["nsqsupe"]="⋣",
-["ubrcy"]="ў",
-["Gscr"]="𝒢",
-["HARDcy"]="Ъ",
-["jopf"]="𝕛",
-["gtquest"]="⩼",
-["iinfin"]="⧜",
-["twixt"]="≬",
+["Escr"]="ℰ",
+["boxvH"]="╪",
+["Ifr"]="ℑ",
+["mp"]="∓",
+["ell"]="ℓ",
+["Iacute"]="Í",
+["NotNestedGreaterGreater"]="⪢̸",
+["raquo"]="»",
+["Zcy"]="З",
+["micro"]="µ",
+["dzigrarr"]="⟿",
+["rtrif"]="▸",
+["Uuml"]="Ü",
+["nvHarr"]="⤄",
+["leqslant"]="⩽",
+["tritime"]="⨻",
+["nlarr"]="↚",
+["NotRightTriangle"]="⋫",
+["apid"]="≋",
+["succeq"]="⪰",
+["NotEqualTilde"]="≂̸",
+["varphi"]="ϕ",
+["Vert"]="‖",
+["int"]="∫",
+["lurdshar"]="⥊",
+["lneqq"]="≨",
+["Jsercy"]="Ј",
+["Superset"]="⊃",
+["subsetneqq"]="⫋",
+["gap"]="⪆",
+["ssmile"]="⌣",
+["Ugrave"]="Ù",
+["IOcy"]="Ё",
+["ltimes"]="⋉",
+["UnderBracket"]="⎵",
+["subseteqq"]="⫅",
+["Dscr"]="𝒟",
+["dtrif"]="▾",
+["raquo"]="»",
+["hbar"]="ℏ",
+["ge"]="≥",
+["cudarrr"]="⤵",
+["icy"]="и",
+["plusdo"]="∔",
+["bull"]="•",
+["weierp"]="℘",
+["mapsto"]="↦",
+["Uring"]="Ů",
+["supplus"]="⫀",
+["Succeeds"]="≻",
+["Ascr"]="𝒜",
+["cdot"]="ċ",
+["nwarr"]="↖",
+["target"]="⌖",
+["dharr"]="⇂",
+["curlyvee"]="⋎",
+["supE"]="⫆",
+["emsp13"]=" ",
["ltrie"]="⊴",
+["olarr"]="↺",
+["RightTeeVector"]="⥛",
+["Vvdash"]="⊪",
+["larrsim"]="⥳",
+["varsubsetneq"]="⊊︀",
+["Not"]="⫬",
+["CenterDot"]="·",
+["PlusMinus"]="±",
+["aring"]="å",
+["Nscr"]="𝒩",
+["delta"]="δ",
+["npre"]="⪯̸",
+["Vcy"]="В",
+["NotVerticalBar"]="∤",
+["scpolint"]="⨓",
+["rcedil"]="ŗ",
+["Lmidot"]="Ŀ",
+["DScy"]="Ѕ",
+["nsubseteq"]="⊈",
+["ngE"]="≧̸",
+["NotSquareSubsetEqual"]="⋢",
+["edot"]="ė",
+["Ucy"]="У",
+["lessapprox"]="⪅",
+["niv"]="∋",
+["Kscr"]="𝒦",
+["LeftVectorBar"]="⥒",
+["nhpar"]="⫲",
+["scedil"]="ş",
+["Uacute"]="Ú",
+["ntrianglelefteq"]="⋬",
+["Otilde"]="Õ",
+["iexcl"]="¡",
+["lbrke"]="⦋",
+["simdot"]="⩪",
+["sigmaf"]="ς",
+["Bfr"]="𝔅",
+["pitchfork"]="⋔",
+["ngeqslant"]="⩾̸",
+["Pscr"]="𝒫",
+["gsime"]="⪎",
+["Ouml"]="Ö",
+["rarrsim"]="⥴",
+["subE"]="⫅",
+["otimesas"]="⨶",
+["lfloor"]="⌊",
+["prop"]="∝",
+["imacr"]="ī",
+["blacktriangleleft"]="◂",
+["Ntilde"]="Ñ",
+["llarr"]="⇇",
+["nsucc"]="⊁",
+["PartialD"]="∂",
+["Iacute"]="Í",
+["gdot"]="ġ",
+["Afr"]="𝔄",
+["Igrave"]="Ì",
["csub"]="⫏",
-["Hscr"]="ℋ",
-["leftharpoondown"]="↽",
+["Mscr"]="ℳ",
+["Scy"]="С",
+["bsime"]="⋍",
+["nequiv"]="≢",
+["scnap"]="⪺",
+["Tab"]=" ",
+["Equal"]="⩵",
+["blacklozenge"]="⧫",
+["nrarrc"]="⤳̸",
+["divide"]="÷",
["RightUpDownVector"]="⥏",
-["LongLeftRightArrow"]="⟷",
-["Im"]="ℑ",
-["dcaron"]="ď",
+["iinfin"]="⧜",
+["precnapprox"]="⪹",
+["dArr"]="⇓",
+["orslope"]="⩗",
+["Rcy"]="Р",
+["sqsub"]="⊏",
+["OverBracket"]="⎴",
+["sum"]="∑",
+["ncedil"]="ņ",
+["ltrPar"]="⦖",
+["ii"]="ⅈ",
+["Gcirc"]="Ĝ",
+["SucceedsTilde"]="≿",
+["RightFloor"]="⌋",
+["osol"]="⊘",
["barwedge"]="⌅",
-["nexist"]="∄",
-["blacktriangledown"]="▾",
-["fork"]="⋔",
-["rhard"]="⇁",
-["cent"]="¢",
-["RightTriangle"]="⊳",
-["Eta"]="Η",
-["dotminus"]="∸",
-["nles"]="⩽̸",
-["larrtl"]="↢",
-["LeftTriangleEqual"]="⊴",
-["hopf"]="𝕙",
-["gammad"]="ϝ",
-["gsime"]="⪎",
-["llhard"]="⥫",
-["precapprox"]="⪷",
-["profalar"]="⌮",
-["lnE"]="≨",
-["ddagger"]="‡",
-["leq"]="≤",
-["smile"]="⌣",
-["robrk"]="⟧",
-["Jscr"]="𝒥",
-["triangleleft"]="◃",
-["acd"]="∿",
-["prod"]="∏",
-["atilde"]="ã",
-["seArr"]="⇘",
-["therefore"]="∴",
-["iopf"]="𝕚",
-["solbar"]="⌿",
-["kcedil"]="ķ",
-["NotHumpEqual"]="≏̸",
-["nspar"]="∦",
-["frac14"]="¼",
-["nsime"]="≄",
-["DoubleLongLeftArrow"]="⟸",
-["sccue"]="≽",
-["models"]="⊧",
-["SupersetEqual"]="⊇",
-["iquest"]="¿",
-["oline"]="‾",
-["lparlt"]="⦓",
-["triplus"]="⨹",
-["nequiv"]="≢",
-["nlE"]="≦̸",
-["nldr"]="‥",
-["equals"]="=",
-["Agrave"]="À",
-["ccaron"]="č",
-["Yacute"]="Ý",
-["Oslash"]="Ø",
-["udarr"]="⇅",
-["ang"]="∠",
-["dopf"]="𝕕",
-["comp"]="∁",
-["caps"]="∩︀",
-["bowtie"]="⋈",
-["glj"]="⪤",
-["ltquest"]="⩻",
-["cirmid"]="⫯",
-["ordm"]="º",
-["esim"]="≂",
-["reals"]="ℝ",
-["LeftTriangle"]="⊲",
-["flat"]="♭",
-["eopf"]="𝕖",
-["lap"]="⪅",
-["not"]="¬",
-["ENG"]="Ŋ",
-["DiacriticalAcute"]="´",
-["sharp"]="♯",
-["longleftarrow"]="⟵",
-["dblac"]="˝",
-["UpArrow"]="↑",
-["npre"]="⪯̸",
-["bopf"]="𝕓",
-["DScy"]="Ѕ",
+["twoheadrightarrow"]="↠",
+["Gscr"]="𝒢",
+["acy"]="а",
+["dtdot"]="⋱",
+["rbrke"]="⦌",
+["imath"]="ı",
+["Hcirc"]="Ĥ",
+["num"]="#",
+["nprec"]="⊀",
+["smallsetminus"]="∖",
+["lesges"]="⪓",
+["LeftUpVector"]="↿",
+["gtdot"]="⋗",
+["theta"]="θ",
+["kappav"]="ϰ",
+["jmath"]="ȷ",
+["Lscr"]="ℒ",
+["Aogon"]="Ą",
+["ltrif"]="◂",
+["DownArrowUpArrow"]="⇵",
+["prap"]="⪷",
+["Racute"]="Ŕ",
+["curlyeqprec"]="⋞",
["bepsi"]="϶",
-["angrtvb"]="⊾",
-["ccaps"]="⩍",
-["UnderParenthesis"]="⏝",
-["subne"]="⊊",
-["succnsim"]="⋩",
-["Bumpeq"]="≎",
-["xvee"]="⋁",
-["colon"]=":",
-["deg"]="°",
-["fnof"]="ƒ",
-["Uarr"]="↟",
-["Zcaron"]="Ž",
-["copf"]="𝕔",
-["Theta"]="Θ",
-["omicron"]="ο",
-["ntriangleright"]="⋫",
-["DoubleLongRightArrow"]="⟹",
-["UnderBrace"]="⏟",
-["GT"]=">",
-["lEg"]="⪋",
-["supplus"]="⫀",
-["acute"]="´",
+["blacktriangle"]="▴",
+["nvap"]="≍⃒",
+["Supset"]="⋑",
+["angmsd"]="∡",
+["boxul"]="┘",
+["LessSlantEqual"]="⩽",
["GT"]=">",
-["upsilon"]="υ",
-["sc"]="≻",
-["xrarr"]="⟶",
-["eng"]="ŋ",
-["it"]="⁢",
-["Ntilde"]="Ñ",
-["Mu"]="Μ",
-["CircleTimes"]="⊗",
-["NotTildeTilde"]="≉",
-["NotLessLess"]="≪̸",
-["vellip"]="⋮",
-["cularrp"]="⤽",
-["UnderBracket"]="⎵",
-["aopf"]="𝕒",
-["itilde"]="ĩ",
-["latail"]="⤙",
-["Nu"]="Ν",
-["Ascr"]="𝒜",
-["complement"]="∁",
-["gjcy"]="ѓ",
-["radic"]="√",
-["maltese"]="✠",
-["glE"]="⪒",
-["plusmn"]="±",
-["curvearrowright"]="↷",
-["gt"]=">",
-["Colone"]="⩴",
-["Bscr"]="ℬ",
-["ic"]="⁣",
-["clubsuit"]="♣",
-["djcy"]="ђ",
-["Oopf"]="𝕆",
-["ltrPar"]="⦖",
-["ngtr"]="≯",
-["eqcirc"]="≖",
-["Hacek"]="ˇ",
-["vdash"]="⊢",
-["NotCupCap"]="≭",
-["Gdot"]="Ġ",
-["jsercy"]="ј",
-["marker"]="▮",
+["nexist"]="∄",
+["ccupssm"]="⩐",
+["Eacute"]="É",
+["ddarr"]="⇊",
+["ntlg"]="≸",
+["Iscr"]="ℐ",
+["Jcirc"]="Ĵ",
+["Sacute"]="Ś",
+["capand"]="⩄",
+["gesdoto"]="⪂",
+["olcross"]="⦻",
+["amalg"]="⨿",
+["rarrlp"]="↬",
+["NotLeftTriangle"]="⋪",
+["reals"]="ℝ",
+["bigcup"]="⋃",
+["NJcy"]="Њ",
+["Odblac"]="Ő",
+["hArr"]="⇔",
+["RightArrowLeftArrow"]="⇄",
+["SOFTcy"]="Ь",
+["Lambda"]="Λ",
+["RightCeiling"]="⌉",
+["Vdash"]="⊩",
+["elinters"]="⏧",
+["lsimg"]="⪏",
["Nopf"]="ℕ",
-["Wfr"]="𝔚",
-["boxHD"]="╦",
-["mho"]="℧",
-["ulcrop"]="⌏",
-["DifferentialD"]="ⅆ",
-["aacute"]="á",
-["lpar"]="(",
+["Esim"]="⩳",
+["vzigzag"]="⦚",
+["acd"]="∿",
+["ccedil"]="ç",
+["lbarr"]="⤌",
+["nmid"]="∤",
+["Backslash"]="∖",
+["Laplacetrf"]="ℒ",
+["npr"]="⊀",
+["nap"]="≉",
+["nsupseteqq"]="⫆̸",
+["igrave"]="ì",
+["LJcy"]="Љ",
+["lessgtr"]="≶",
["angle"]="∠",
-["rharu"]="⇀",
-["Breve"]="˘",
-["Dot"]="¨",
-["rect"]="▭",
-["NotNestedLessLess"]="⪡̸",
-["boxplus"]="⊞",
-["NotSucceeds"]="⊁",
-["gnapprox"]="⪊",
-["DownLeftTeeVector"]="⥞",
-["Xfr"]="𝔛",
-["Lang"]="⟪",
-["Element"]="∈",
-["sung"]="♪",
-["RightVectorBar"]="⥓",
-["simne"]="≆",
-["LeftVector"]="↼",
-["Idot"]="İ",
+["lAarr"]="⇚",
+["notin"]="∉",
+["orv"]="⩛",
+["gtreqqless"]="⪌",
+["CircleMinus"]="⊖",
+["Diamond"]="⋄",
+["map"]="↦",
+["nvsim"]="∼⃒",
+["pi"]="π",
+["pluscir"]="⨢",
+["boxVH"]="╬",
["QUOT"]="\"",
-["nsmid"]="∤",
-["fjlig"]="fj",
-["Ufr"]="𝔘",
-["cuvee"]="⋎",
+["duarr"]="⇵",
+["lgE"]="⪑",
+["lmoust"]="⎰",
+["lsquo"]="‘",
+["rightrightarrows"]="⇉",
+["times"]="×",
+["iuml"]="ï",
+["andslope"]="⩘",
+["order"]="ℴ",
+["Sub"]="⋐",
+["capcap"]="⩋",
+["nabla"]="∇",
+["ntriangleleft"]="⋪",
+["blk14"]="░",
+["Kopf"]="𝕂",
+["lArr"]="⇐",
+["Qopf"]="ℚ",
+["circledS"]="Ⓢ",
+["omid"]="⦶",
+["ord"]="⩝",
+["lvertneqq"]="≨︀",
+["updownarrow"]="↕",
+["yacute"]="ý",
+["ni"]="∋",
+["hamilt"]="ℋ",
+["Jopf"]="𝕁",
+["CupCap"]="≍",
+["lbrack"]="[",
+["preccurlyeq"]="≼",
+["Ropf"]="ℝ",
+["lessdot"]="⋖",
+["blank"]="␣",
+["SucceedsEqual"]="⪰",
+["triangleleft"]="◃",
+["ring"]="˚",
+["omega"]="ω",
+["bowtie"]="⋈",
+["Sqrt"]="√",
+["uuml"]="ü",
+["Udblac"]="Ű",
+["diams"]="♦",
+["Oslash"]="Ø",
["real"]="ℜ",
-["luruhar"]="⥦",
-["NotRightTriangleBar"]="⧐̸",
-["target"]="⌖",
-["lharu"]="↼",
-["CloseCurlyQuote"]="’",
-["rAtail"]="⤜",
-["nparallel"]="∦",
-["brvbar"]="¦",
-["Vfr"]="𝔙",
-["wedbar"]="⩟",
-["REG"]="®",
-["boxur"]="└",
-["Rcaron"]="Ř",
-["Rang"]="⟫",
-["sqsubseteq"]="⊑",
-["div"]="÷",
-["boxul"]="┘",
-["Cdot"]="Ċ",
-["vsupnE"]="⫌︀",
-["zeetrf"]="ℨ",
-["Sfr"]="𝔖",
-["roang"]="⟭",
-["LessTilde"]="≲",
-["equiv"]="≡",
-["frac12"]="½",
-["eacute"]="é",
-["rrarr"]="⇉",
-["nearhk"]="⤤",
-["Zopf"]="ℤ",
-["SucceedsTilde"]="≿",
+["egrave"]="è",
+["prurel"]="⊰",
+["LeftUpDownVector"]="⥑",
+["TildeEqual"]="≃",
+["cuwed"]="⋏",
+["times"]="×",
["ap"]="≈",
-["lfisht"]="⥼",
-["timesd"]="⨰",
-["UpDownArrow"]="↕",
-["xuplus"]="⨄",
-["cularr"]="↶",
-["iprod"]="⨼",
-["AElig"]="Æ",
-["rationals"]="ℚ",
-["geqq"]="≧",
-["Tfr"]="𝔗",
-["Yopf"]="𝕐",
-["rtimes"]="⋊",
-["Tcaron"]="Ť",
-["srarr"]="→",
-["diam"]="⋄",
-["mid"]="∣",
-["imath"]="ı",
-["PlusMinus"]="±",
-["isin"]="∈",
-["vprop"]="∝",
-["RightArrowLeftArrow"]="⇄",
-["NotSubset"]="⊂⃒",
-["bigtriangledown"]="▽",
-["ldsh"]="↲",
-["Qfr"]="𝔔",
-["nvap"]="≍⃒",
-["vert"]="|",
-["Xopf"]="𝕏",
-["lBarr"]="⤎",
-["egsdot"]="⪘",
-["Tcedil"]="Ţ",
-["xi"]="ξ",
-["LeftUpVectorBar"]="⥘",
-["circ"]="ˆ",
-["ocir"]="⊚",
-["gtlPar"]="⦕",
-["Rfr"]="ℜ",
-["RightTriangleBar"]="⧐",
-["nwarhk"]="⤣",
-["zhcy"]="ж",
-["Iukcy"]="І",
-["plusdo"]="∔",
+["lowast"]="∗",
+["Lopf"]="𝕃",
+["bdquo"]="„",
+["blacktriangledown"]="▾",
+["vBarv"]="⫩",
+["Longleftarrow"]="⟸",
+["lesg"]="⋚︀",
+["Popf"]="ℙ",
+["iogon"]="į",
+["vellip"]="⋮",
+["Ntilde"]="Ñ",
+["cwconint"]="∲",
["boxv"]="│",
-["minusb"]="⊟",
-["Ncaron"]="Ň",
-["angmsdaa"]="⦨",
-["varsubsetneqq"]="⫋︀",
-["cirfnint"]="⨐",
-["LongRightArrow"]="⟶",
-["ddarr"]="⇊",
-["piv"]="ϖ",
-["fopf"]="𝕗",
-["Ofr"]="𝔒",
-["fflig"]="ff",
-["Jukcy"]="Є",
-["xhArr"]="⟺",
-["ncy"]="н",
-["Scaron"]="Š",
-["TildeEqual"]="≃",
-["subrarr"]="⥹",
-["iacute"]="í",
-["ogt"]="⧁",
-["nvge"]="≥⃒",
-["vee"]="∨",
-["UnderBar"]="_",
-["andslope"]="⩘",
-["gopf"]="𝕘",
-["Pfr"]="𝔓",
-["die"]="¨",
+["boxbox"]="⧉",
+["langd"]="⦑",
+["diam"]="⋄",
+["boxHu"]="╧",
+["acute"]="´",
["Uopf"]="𝕌",
+["Fcy"]="Ф",
+["vee"]="∨",
+["eqslantless"]="⪕",
+["NotLeftTriangleEqual"]="⋬",
+["OverBrace"]="⏞",
+["beta"]="β",
+["Otilde"]="Õ",
+["fjlig"]="fj",
+["uacute"]="ú",
+["CirclePlus"]="⊕",
+["Mellintrf"]="ℳ",
+["Vopf"]="𝕍",
+["Gcy"]="Г",
+["searhk"]="⤥",
+["boxur"]="└",
+["LeftTeeVector"]="⥚",
+["nsubE"]="⫅̸",
+["gvertneqq"]="≩︀",
+["eqcirc"]="≖",
+["nrightarrow"]="↛",
+["DJcy"]="Ђ",
+["tdot"]="⃛",
+["Dcy"]="Д",
+["Sopf"]="𝕊",
+["range"]="⦥",
+["agrave"]="à",
+["gtrsim"]="≳",
["RightArrowBar"]="⇥",
-["orarr"]="↻",
-["Precedes"]="≺",
-["oror"]="⩖",
-["straightepsilon"]="ϵ",
-["cong"]="≅",
-["TScy"]="Ц",
-["nleftarrow"]="↚",
-["DZcy"]="Џ",
-["horbar"]="―",
+["larrlp"]="↫",
+["le"]="≤",
+["xi"]="ξ",
+["gla"]="⪥",
+["GT"]=">",
+["leftarrowtail"]="↢",
+["commat"]="@",
+["rightarrowtail"]="↣",
+["approx"]="≈",
+["sdot"]="⋅",
["Topf"]="𝕋",
-["Cayleys"]="ℭ",
-["leqq"]="≦",
-["curlyeqprec"]="⋞",
-["nLeftarrow"]="⇍",
-["pcy"]="п",
-["realine"]="ℛ",
-["nlsim"]="≴",
+["Ecy"]="Э",
+["eplus"]="⩱",
+["cir"]="○",
["Rarrtl"]="⤖",
-["CupCap"]="≍",
-["vDash"]="⊨",
-["shortparallel"]="∥",
-["ExponentialE"]="ⅇ",
-["Sopf"]="𝕊",
-["iiota"]="℩",
-["Nfr"]="𝔑",
-["pointint"]="⨕",
-["NotGreaterLess"]="≹",
-["olcross"]="⦻",
-["kcy"]="к",
-["complexes"]="ℂ",
-["varepsilon"]="ϵ",
-["Fouriertrf"]="ℱ",
-["rho"]="ρ",
-["Lsh"]="↰",
-["exponentiale"]="ⅇ",
-["hookrightarrow"]="↪",
-["Ropf"]="ℝ",
-["lAtail"]="⤛",
-["Kfr"]="𝔎",
-["bsim"]="∽",
-["jcy"]="й",
-["frac34"]="¾",
-["DotDot"]="⃜",
+["Emacr"]="Ē",
+["Dcaron"]="Ď",
+["Sc"]="⪼",
+["cent"]="¢",
+["rtri"]="▹",
+["cedil"]="¸",
+["spades"]="♠",
+["upsilon"]="υ",
+["boxminus"]="⊟",
+["angmsdaa"]="⦨",
+["zdot"]="ż",
+["Bcy"]="Б",
+["Zscr"]="𝒵",
+["looparrowleft"]="↫",
+["Dfr"]="𝔇",
+["Bumpeq"]="≎",
+["nLeftarrow"]="⇍",
+["equiv"]="≡",
+["Ccaron"]="Č",
+["UpperLeftArrow"]="↖",
+["SubsetEqual"]="⊆",
+["nrArr"]="⇏",
+["loarr"]="⇽",
+["minusdu"]="⨪",
+["sup3"]="³",
+["Zopf"]="ℤ",
+["elsdot"]="⪗",
+["NotLessLess"]="≪̸",
+["eta"]="η",
+["ubrcy"]="ў",
+["Yscr"]="𝒴",
+["subset"]="⊂",
+["Cfr"]="ℭ",
+["harrcir"]="⥈",
+["supsetneq"]="⊋",
+["LeftUpVectorBar"]="⥘",
+["LT"]="<",
+["DoubleLeftArrow"]="⇐",
+["circledcirc"]="⊚",
+["bkarow"]="⤍",
+["rangd"]="⦒",
+["downharpoonright"]="⇂",
+["Wopf"]="𝕎",
+["ast"]="*",
+["planck"]="ℏ",
+["gtrdot"]="⋗",
+["Ffr"]="𝔉",
+["rArr"]="⇒",
+["VeryThinSpace"]=" ",
+["Ecaron"]="Ě",
+["RightVectorBar"]="⥓",
+["divonx"]="⋇",
+["Xopf"]="𝕏",
+["nsubset"]="⊂⃒",
+["Otimes"]="⨷",
+["bot"]="⊥",
+["nsime"]="≄",
["thorn"]="þ",
-["ThickSpace"]="  ",
-["SquareUnion"]="⊔",
-["frac58"]="⅝",
-["dfisht"]="⥿",
-["MediumSpace"]=" ",
-["Lfr"]="𝔏",
-["Qopf"]="ℚ",
+["subsetneq"]="⊊",
+["nltri"]="⋪",
+["Cayleys"]="ℭ",
+["Efr"]="𝔈",
+["Intersection"]="⋂",
+["UnderBar"]="_",
+["fpartint"]="⨍",
+["Iuml"]="Ï",
+["rsquo"]="’",
+["ecir"]="≖",
+["nis"]="⋼",
+["fscr"]="𝒻",
+["hellip"]="…",
+["ogt"]="⧁",
["ntgl"]="≹",
-["LessFullEqual"]="≦",
-["malt"]="✠",
-["mcy"]="м",
-["NotGreaterEqual"]="≱",
-["bottom"]="⊥",
-["NotSucceedsEqual"]="⪰̸",
-["lcedil"]="ļ",
-["infintie"]="⧝",
-["Lcaron"]="Ľ",
-["NotSquareSubset"]="⊏̸",
-["brvbar"]="¦",
-["fallingdotseq"]="≒",
-["AElig"]="Æ",
-["swarhk"]="⤦",
-["Ifr"]="ℑ",
-["pi"]="π",
-["lcy"]="л",
-["copy"]="©",
-["dlcorn"]="⌞",
-["oacute"]="ó",
-["gtreqless"]="⋛",
-["neArr"]="⇗",
+["frac14"]="¼",
+["squf"]="▪",
+["circ"]="ˆ",
+["prE"]="⪳",
+["ordf"]="ª",
["ZHcy"]="Ж",
-["Vdashl"]="⫦",
-["darr"]="↓",
-["circeq"]="≗",
+["NegativeVeryThinSpace"]="​",
+["quot"]="\"",
+["excl"]="!",
+["sqcaps"]="⊓︀",
+["gfr"]="𝔤",
+["varsigma"]="ς",
+["nwarrow"]="↖",
+["reg"]="®",
+["longmapsto"]="⟼",
+["And"]="⩓",
+["cuvee"]="⋎",
+["zwj"]="‍",
+["plankv"]="ℏ",
+["varepsilon"]="ϵ",
+["Aopf"]="𝔸",
+["UpTee"]="⊥",
+["lescc"]="⪨",
+["ltri"]="◃",
+["iiint"]="∭",
+["ccups"]="⩌",
+["alefsym"]="ℵ",
+["succneqq"]="⪶",
+["hscr"]="𝒽",
+["Or"]="⩔",
["yuml"]="ÿ",
-["Jfr"]="𝔍",
-["Product"]="∏",
-["boxDL"]="╗",
-["el"]="⪙",
-["supe"]="⊇",
-["frac13"]="⅓",
-["Barwed"]="⌆",
-["larrpl"]="⤹",
-["SHCHcy"]="Щ",
-["LeftUpDownVector"]="⥑",
-["Diamond"]="⋄",
-["DownLeftVectorBar"]="⥖",
-["Cross"]="⨯",
-["ncup"]="⩂",
-["supnE"]="⫌",
-["lne"]="⪇",
-["micro"]="µ",
-["lowbar"]="_",
-["perp"]="⊥",
-["sqcap"]="⊓",
-["Gfr"]="𝔊",
-["raemptyv"]="⦳",
-["gesl"]="⋛︀",
-["drcrop"]="⌌",
-["boxUL"]="╝",
-["becaus"]="∵",
-["gne"]="⪈",
-["scap"]="⪸",
-["swarrow"]="↙",
-["nesim"]="≂̸",
-["DoubleDot"]="¨",
-["Mopf"]="𝕄",
-["apid"]="≋",
-["InvisibleComma"]="⁣",
-["Backslash"]="∖",
-["mnplus"]="∓",
-["niv"]="∋",
-["Hfr"]="ℌ",
-["rarrlp"]="↬",
-["Because"]="∵",
-["parsl"]="⫽",
-["sup1"]="¹",
-["Lt"]="≪",
-["par"]="∥",
-["Iota"]="Ι",
-["beth"]="ℶ",
-["Lopf"]="𝕃",
+["rcub"]="}",
+["lt"]="<",
+["vArr"]="⇕",
+["EqualTilde"]="≂",
+["vDash"]="⊨",
+["RightArrow"]="→",
+["dlcorn"]="⌞",
+["Barv"]="⫧",
+["nsc"]="⊁",
+["Proportion"]="∷",
+["iota"]="ι",
+["gscr"]="ℊ",
+["abreve"]="ă",
+["ThickSpace"]="  ",
+["szlig"]="ß",
+["lhard"]="↽",
+["emptyv"]="∅",
+["Tau"]="Τ",
+["sharp"]="♯",
+["bNot"]="⫭",
+["LongLeftRightArrow"]="⟷",
+["frac23"]="⅔",
+["NotEqual"]="≠",
+["scE"]="⪴",
+["jfr"]="𝔧",
+["bscr"]="𝒷",
+["uhblk"]="▀",
+["frac35"]="⅗",
+["TSHcy"]="Ћ",
+["ntrianglerighteq"]="⋭",
+["Tcedil"]="Ţ",
+["NotGreaterFullEqual"]="≧̸",
+["asympeq"]="≍",
+["oror"]="⩖",
+["ecirc"]="ê",
+["ohbar"]="⦵",
+["Rho"]="Ρ",
+["iacute"]="í",
+["ascr"]="𝒶",
+["RightUpVector"]="↾",
+["Ocirc"]="Ô",
+["cedil"]="¸",
+["sect"]="§",
+["angmsdab"]="⦩",
+["FilledVerySmallSquare"]="▪",
+["curlywedge"]="⋏",
+["lesdotor"]="⪃",
+["esdot"]="≐",
+["eqvparsl"]="⧥",
["Cap"]="⋒",
-["Aring"]="Å",
-["rarr"]="→",
-["Efr"]="𝔈",
-["bigcup"]="⋃",
-["DownLeftRightVector"]="⥐",
-["lesges"]="⪓",
-["NegativeThinSpace"]="​",
-["DownRightTeeVector"]="⥟",
-["npolint"]="⨔",
-["gEl"]="⪌",
-["lltri"]="◺",
-["ogon"]="˛",
-["LessEqualGreater"]="⋚",
-["sqsupset"]="⊐",
-["NotSubsetEqual"]="⊈",
-["Ubrcy"]="Ў",
-["ShortDownArrow"]="↓",
-["ugrave"]="ù",
-["Dcaron"]="Ď",
-["subE"]="⫅",
-["divide"]="÷",
-["bigotimes"]="⨂",
-["dscy"]="ѕ",
-["wreath"]="≀",
-["Jopf"]="𝕁",
-["pre"]="⪯",
-["tdot"]="⃛",
-["Cfr"]="ℭ",
-["Uogon"]="Ų",
-["softcy"]="ь",
-["isinE"]="⋹",
-["Dstrok"]="Đ",
-["Jsercy"]="Ј",
-["capdot"]="⩀",
-["realpart"]="ℜ",
-["hearts"]="♥",
-["Atilde"]="Ã",
-["LeftArrowRightArrow"]="⇆",
-["upharpoonleft"]="↿",
-["Iopf"]="𝕀",
-["Intersection"]="⋂",
-["midcir"]="⫰",
-["ocirc"]="ô",
-["sdot"]="⋅",
-["Dfr"]="𝔇",
-["gla"]="⪥",
-["DiacriticalGrave"]="`",
+["dscr"]="𝒹",
+["rbrace"]="}",
+["nsccue"]="⋡",
+["neArr"]="⇗",
+["rightthreetimes"]="⋌",
+["plusmn"]="±",
["Ubreve"]="Ŭ",
-["int"]="∫",
-["PrecedesSlantEqual"]="≼",
-["Square"]="□",
-["Acy"]="А",
+["ifr"]="𝔦",
+["Poincareplane"]="ℌ",
+["leftrightarrows"]="⇆",
+["scnsim"]="⋩",
+["cscr"]="𝒸",
+["NotHumpEqual"]="≏̸",
+["capbrcup"]="⩉",
+["curarr"]="↷",
+["notinvb"]="⋷",
+["LeftArrow"]="←",
+["Gopf"]="𝔾",
+["ldrushar"]="⥋",
+["nscr"]="𝓃",
+["Gg"]="⋙",
+["ouml"]="ö",
+["nsce"]="⪰̸",
+["cupbrcap"]="⩈",
+["nLt"]="≪⃒",
+["bullet"]="•",
+["nsqsupe"]="⋣",
+["rect"]="▭",
+["lbrace"]="{",
+["Fopf"]="𝔽",
+["COPY"]="©",
+["epar"]="⋕",
+["mscr"]="𝓂",
+["odsold"]="⦼",
+["cupor"]="⩅",
+["not"]="¬",
+["subsim"]="⫇",
+["hoarr"]="⇿",
+["Scedil"]="Ş",
+["eacute"]="é",
+["emsp"]=" ",
+["uml"]="¨",
+["igrave"]="ì",
+["pscr"]="𝓅",
+["LeftTee"]="⊣",
+["Cedilla"]="¸",
+["Iopf"]="𝕀",
+["HumpEqual"]="≏",
+["les"]="⩽",
+["Rcedil"]="Ŗ",
+["lsquor"]="‚",
+["raemptyv"]="⦳",
+["NotSucceedsSlantEqual"]="⋡",
+["SuchThat"]="∋",
+["vert"]="|",
+["backcong"]="≌",
["Hopf"]="ℍ",
-["precsim"]="≾",
-["nleq"]="≰",
-["urcorn"]="⌝",
-["hyphen"]="‐",
-["FilledSmallSquare"]="◼",
-["zdot"]="ż",
-["ndash"]="–",
-["hbar"]="ℏ",
-["Wopf"]="𝕎",
-["Esim"]="⩳",
-["subsetneq"]="⊊",
-["boxhD"]="╥",
-["searhk"]="⤥",
-["late"]="⪭",
+["CircleDot"]="⊙",
+["Kappa"]="Κ",
+["conint"]="∮",
+["DZcy"]="Џ",
+["prsim"]="≾",
+["Copf"]="ℂ",
+["curvearrowright"]="↷",
+["twixt"]="≬",
+["curren"]="¤",
+["rtriltri"]="⧎",
+["jscr"]="𝒿",
+["cupcup"]="⩊",
+["Lcedil"]="Ļ",
+["supseteqq"]="⫆",
+["bfr"]="𝔟",
+["lesseqqgtr"]="⪋",
+["leftleftarrows"]="⇇",
+["Bopf"]="𝔹",
+["acute"]="´",
["blacktriangleright"]="▸",
-["auml"]="ä",
-["NotLessTilde"]="≴",
-["Bfr"]="𝔅",
-["grave"]="`",
-["ltlarr"]="⥶",
-["Aogon"]="Ą",
-["sdote"]="⩦",
-["gtrsim"]="≳",
-["nvinfin"]="⧞",
-["lgE"]="⪑",
-["mdash"]="—",
-["Vopf"]="𝕍",
-["leftrightarrow"]="↔",
-["RBarr"]="⤐",
-["amalg"]="⨿",
-["preccurlyeq"]="≼",
-["EqualTilde"]="≂",
-["scpolint"]="⨓",
-["NotHumpDownHump"]="≎̸",
-["uparrow"]="↑",
-["downarrow"]="↓",
-["boxdL"]="╕",
-["Hstrok"]="Ħ",
-["Ccaron"]="Č",
-["succsim"]="≿",
-["RightFloor"]="⌋",
-["DownBreve"]="̑",
-["succapprox"]="⪸",
-["dsol"]="⧶",
-["napid"]="≋̸",
-["nprcue"]="⋠",
+["frac34"]="¾",
+["Gbreve"]="Ğ",
+["Updownarrow"]="⇕",
+["iscr"]="𝒾",
+["sigmav"]="ς",
+["trade"]="™",
+["minusb"]="⊟",
+["GJcy"]="Ѓ",
+["TildeFullEqual"]="≅",
+["DoubleRightTee"]="⊨",
+["nang"]="∠⃒",
+["ddotseq"]="⩷",
+["copy"]="©",
["Eopf"]="𝔼",
-["ell"]="ℓ",
-["cupdot"]="⊍",
-["Not"]="⫬",
-["zigrarr"]="⇝",
-["downharpoonright"]="⇂",
-["nisd"]="⋺",
-["lotimes"]="⨴",
-["plusmn"]="±",
-["ngE"]="≧̸",
-["odash"]="⊝",
-["emptyset"]="∅",
+["Psi"]="Ψ",
+["UpperRightArrow"]="↗",
+["geqq"]="≧",
+["subedot"]="⫃",
+["nvlArr"]="⤂",
+["Ncedil"]="Ņ",
+["vsupne"]="⊋︀",
+["supset"]="⊃",
["squarf"]="▪",
-["NotGreaterTilde"]="≵",
-["NotTildeFullEqual"]="≇",
-["DownArrowUpArrow"]="⇵",
-["nwarrow"]="↖",
-["looparrowright"]="↬",
+["LeftDoubleBracket"]="⟦",
+["utrif"]="▴",
["Dopf"]="𝔻",
-["oplus"]="⊕",
-["UpEquilibrium"]="⥮",
-["leftthreetimes"]="⋋",
-["DoubleLeftTee"]="⫤",
-["nabla"]="∇",
-["RuleDelayed"]="⧴",
-["euml"]="ë",
-["varsupsetneqq"]="⫌︀",
-["upsi"]="υ",
-["supsup"]="⫖",
-["bsol"]="\\",
-["Copf"]="ℂ",
-["DDotrahd"]="⤑",
-["Upsilon"]="Υ",
-["UpperRightArrow"]="↗",
-["nedot"]="≐̸",
-["NotEqual"]="≠",
-["bumpeq"]="≏",
-["emsp14"]=" ",
-["frac38"]="⅜",
-["DownTeeArrow"]="↧",
-["Bopf"]="𝔹",
-["capand"]="⩄",
-["nleqq"]="≦̸",
-["ratio"]="∶",
-["eplus"]="⩱",
-["nge"]="≱",
-["laquo"]="«",
-["urtri"]="◹",
-["LeftUpVector"]="↿",
-["gl"]="≷",
-["Gt"]="≫",
-["andd"]="⩜",
+["ape"]="≊",
+["gEl"]="⪌",
+["COPY"]="©",
+["afr"]="𝔞",
+["Acy"]="А",
+["ldquor"]="„",
+["because"]="∵",
+["Pr"]="⪻",
+["OverBar"]="‾",
+["lang"]="⟨",
+["mopf"]="𝕞",
+["crarr"]="↵",
+["Epsilon"]="Ε",
+["Nfr"]="𝔑",
+["kjcy"]="ќ",
+["TildeTilde"]="≈",
+["bsim"]="∽",
+["lcy"]="л",
+["larrb"]="⇤",
+["ncong"]="≇",
+["ENG"]="Ŋ",
+["brvbar"]="¦",
+["Rightarrow"]="⇒",
+["nopf"]="𝕟",
+["Wfr"]="𝔚",
+["ljcy"]="љ",
+["diamondsuit"]="♦",
+["latail"]="⤙",
+["lambda"]="λ",
+["frac14"]="¼",
+["mcy"]="м",
+["nparsl"]="⫽⃥",
+["lBarr"]="⤎",
+["subdot"]="⪽",
+["frac12"]="½",
+["kopf"]="𝕜",
+["LeftCeiling"]="⌈",
+["erarr"]="⥱",
+["pre"]="⪯",
+["varr"]="↕",
+["Pi"]="Π",
+["sub"]="⊂",
+["ncy"]="н",
+["marker"]="▮",
+["rpargt"]="⦔",
+["supe"]="⊇",
+["veebar"]="⊻",
+["checkmark"]="✓",
+["nbsp"]=" ",
+["sqsupseteq"]="⊒",
+["upharpoonright"]="↾",
+["lopf"]="𝕝",
+["Omicron"]="Ο",
+["ccaps"]="⩍",
+["lrhard"]="⥭",
["Lstrok"]="Ł",
-["gamma"]="γ",
-["Sc"]="⪼",
-["Aopf"]="𝔸",
-["pluscir"]="⨢",
-["Itilde"]="Ĩ",
-["DoubleRightTee"]="⊨",
-["pluse"]="⩲",
-["iiint"]="∭",
-["dotplus"]="∔",
-["vrtri"]="⊳",
-["Proportion"]="∷",
-["bne"]="=⃥",
-["cuepr"]="⋞",
+["Mfr"]="𝔐",
+["njcy"]="њ",
+["ocy"]="о",
+["Zcaron"]="Ž",
+["NotSucceeds"]="⊁",
+["rarrbfs"]="⤠",
+["gtrapprox"]="⪆",
+["oS"]="Ⓢ",
+["diamond"]="⋄",
+["gesdot"]="⪀",
+["urcorner"]="⌝",
+["lotimes"]="⨴",
+["pertenk"]="‱",
+["rfisht"]="⥽",
+["Zfr"]="ℨ",
+["Map"]="⤅",
+["cross"]="✗",
+["DifferentialD"]="ⅆ",
+["boxtimes"]="⊠",
+["horbar"]="―",
+["lg"]="≶",
+["orarr"]="↻",
+["Vbar"]="⫫",
+["ropf"]="𝕣",
+["NotDoubleVerticalBar"]="∦",
+["Sfr"]="𝔖",
+["Iuml"]="Ï",
+["leftharpoondown"]="↽",
+["atilde"]="ã",
+["VerticalTilde"]="≀",
+["DoubleContourIntegral"]="∯",
+["longleftarrow"]="⟵",
+["Im"]="ℑ",
+["RightUpVectorBar"]="⥔",
+["nGg"]="⋙̸",
+["scap"]="⪸",
+["nrarr"]="↛",
+["ycy"]="ы",
+["ucirc"]="û",
+["qopf"]="𝕢",
+["oopf"]="𝕠",
+["yacute"]="ý",
+["Xfr"]="𝔛",
+["fork"]="⋔",
+["in"]="∈",
+["xcap"]="⋂",
+["check"]="✓",
+["jcy"]="й",
+["Phi"]="Φ",
+["doteq"]="≐",
["vBar"]="⫨",
-["yucy"]="ю",
-["PrecedesTilde"]="≾",
-["varr"]="↕",
-["leftarrowtail"]="↢",
-["rangle"]="⟩",
-["subsub"]="⫕",
-["rightarrowtail"]="↣",
-["oslash"]="ø",
-["mapstodown"]="↧",
-["sqsube"]="⊑",
-["NewLine"]="\n",
-["Vdash"]="⊩",
-["num"]="#",
-["umacr"]="ū",
-["InvisibleTimes"]="⁢",
-["bemptyv"]="⦰",
+["frown"]="⌢",
["Iogon"]="Į",
-["ssmile"]="⌣",
-["timesbar"]="⨱",
-["Tstrok"]="Ŧ",
-["Icy"]="И",
-["zacute"]="ź",
-["Cedilla"]="¸",
-["daleth"]="ℸ",
-["semi"]=";",
-["ssetmn"]="∖",
-["subdot"]="⪽",
-["Bernoullis"]="ℬ",
-["otimesas"]="⨶",
-["circleddash"]="⊝",
-["circlearrowright"]="↻",
-["NotLeftTriangleEqual"]="⋬",
-["NotTilde"]="≁",
-["npart"]="∂̸",
-["Gbreve"]="Ğ",
-["gtrless"]="≷",
-["pound"]="£",
-["curlyeqsucc"]="⋟",
-["blacklozenge"]="⧫",
-["ldca"]="⤶",
-["nsucc"]="⊁",
-["top"]="⊤",
-["ufr"]="𝔲",
-["sscr"]="𝓈",
-["eDDot"]="⩷",
-["Updownarrow"]="⇕",
-["loz"]="◊",
-["Gcy"]="Г",
-["boxdl"]="┐",
+["gnsim"]="⋧",
+["nsupset"]="⊃⃒",
+["equals"]="=",
+["angmsdac"]="⦪",
+["odash"]="⊝",
+["Hstrok"]="Ħ",
+["homtht"]="∻",
+["maltese"]="✠",
+["esim"]="≂",
+["realine"]="ℛ",
+["straightepsilon"]="ϵ",
+["utri"]="▵",
+["primes"]="ℙ",
+["dbkarow"]="⤏",
+["NotLessTilde"]="≴",
+["nvrArr"]="⤃",
+["cularrp"]="⤽",
+["supsup"]="⫖",
+["rang"]="⟩",
+["nshortmid"]="∤",
+["NotCupCap"]="≭",
+["gnE"]="≩",
+["otilde"]="õ",
+["LeftTriangle"]="⊲",
+["oelig"]="œ",
+["curarrm"]="⤼",
+["orderof"]="ℴ",
+["DoubleLongLeftArrow"]="⟸",
+["OverParenthesis"]="⏜",
+["amacr"]="ā",
+["copysr"]="℗",
+["acirc"]="â",
+["LeftArrowRightArrow"]="⇆",
+["filig"]="fi",
+["uopf"]="𝕦",
+["rlhar"]="⇌",
+["dharl"]="⇃",
+["rAarr"]="⇛",
+["rarrw"]="↝",
+["isin"]="∈",
+["simg"]="⪞",
+["NoBreak"]="⁠",
+["rAtail"]="⤜",
+["ndash"]="–",
+["IJlig"]="IJ",
+["dfr"]="𝔡",
+["ohm"]="Ω",
+["breve"]="˘",
+["ccedil"]="ç",
+["topf"]="𝕥",
+["nvDash"]="⊭",
+["RBarr"]="⤐",
+["clubs"]="♣",
["napos"]="ʼn",
-["Sqrt"]="√",
-["xsqcup"]="⨆",
-["Implies"]="⇒",
-["uring"]="ů",
-["thetav"]="ϑ",
-["iiiint"]="⨌",
-["nLeftrightarrow"]="⇎",
-["lobrk"]="⟦",
-["xfr"]="𝔵",
-["Abreve"]="Ă",
-["micro"]="µ",
-["quatint"]="⨖",
-["congdot"]="⩭",
-["nrtrie"]="⋭",
-["Fcy"]="Ф",
-["hksearow"]="⤥",
-["LowerLeftArrow"]="↙",
-["rdca"]="⤷",
-["OverBar"]="‾",
-["frac12"]="½",
-["imacr"]="ī",
-["boxVL"]="╣",
-["sfr"]="𝔰",
-["ensp"]=" ",
-["dwangle"]="⦦",
-["boxh"]="─",
-["Eogon"]="Ę",
+["ngtr"]="≯",
+["Tstrok"]="Ŧ",
+["lrarr"]="⇆",
+["eqslantgtr"]="⪖",
+["efr"]="𝔢",
+["gne"]="⪈",
+["csube"]="⫑",
+["Xi"]="Ξ",
+["sopf"]="𝕤",
+["LeftVector"]="↼",
+["ggg"]="⋙",
+["Ubrcy"]="Ў",
+["die"]="¨",
+["topbot"]="⌶",
+["Rfr"]="ℜ",
+["ofcir"]="⦿",
["imped"]="Ƶ",
-["Ecy"]="Э",
-["lates"]="⪭︀",
-["phi"]="φ",
-["minusd"]="∸",
-["planckh"]="ℎ",
-["Ocirc"]="Ô",
-["lE"]="≦",
-["sum"]="∑",
-["lrtri"]="⊿",
-["ruluhar"]="⥨",
-["lAarr"]="⇚",
-["DownArrow"]="↓",
-["zscr"]="𝓏",
-["questeq"]="≟",
-["ngeqq"]="≧̸",
-["And"]="⩓",
-["Dcy"]="Д",
-["angrtvbd"]="⦝",
-["rarrpl"]="⥅",
-["thkap"]="≈",
-["Otimes"]="⨷",
-["lesssim"]="≲",
-["gE"]="≧",
-["ouml"]="ö",
-["nsubseteq"]="⊈",
-["bigcirc"]="◯",
+["plusmn"]="±",
+["nles"]="⩽̸",
+["pcy"]="п",
+["permil"]="‰",
+["notinE"]="⋹̸",
+["bigoplus"]="⨁",
+["boxplus"]="⊞",
+["doublebarwedge"]="⌆",
+["ccaron"]="č",
+["asymp"]="≈",
+["sup1"]="¹",
+["bumpeq"]="≏",
+["nrtrie"]="⋭",
+["larrbfs"]="⤟",
+["emacr"]="ē",
+["gtrless"]="≷",
+["Kfr"]="𝔎",
+["plus"]="+",
+["risingdotseq"]="≓",
+["notindot"]="⋵̸",
+["Subset"]="⋐",
+["CloseCurlyDoubleQuote"]="”",
+["nlsim"]="≴",
+["dcaron"]="ď",
["boxVR"]="╠",
-["Vert"]="‖",
-["naturals"]="ℕ",
-["plussim"]="⨦",
-["wscr"]="𝓌",
-["raquo"]="»",
-["bigodot"]="⨀",
-["dashv"]="⊣",
-["hairsp"]=" ",
-["inodot"]="ı",
-["vnsup"]="⊃⃒",
+["lne"]="⪇",
+["Pfr"]="𝔓",
+["rightsquigarrow"]="↝",
+["phone"]="☎",
+["DiacriticalDot"]="˙",
+["Congruent"]="≡",
+["SquareIntersection"]="⊓",
+["ordf"]="ª",
+["loz"]="◊",
["cire"]="≗",
-["vartriangleleft"]="⊲",
-["rbrke"]="⦌",
-["boxuL"]="╛",
-["sce"]="⪰",
-["nrtri"]="⋫",
-["loarr"]="⇽",
-["ShortRightArrow"]="→",
-["xscr"]="𝓍",
-["Bcy"]="Б",
-["HumpEqual"]="≏",
-["lmidot"]="ŀ",
-["DownLeftVector"]="↽",
-["leftharpoonup"]="↼",
+["ecaron"]="ě",
+["nsub"]="⊄",
+["Fouriertrf"]="ℱ",
+["Qfr"]="𝔔",
+["dblac"]="˝",
+["sc"]="≻",
+["xrarr"]="⟶",
+["ImaginaryI"]="ⅈ",
+["angmsdag"]="⦮",
+["wopf"]="𝕨",
+["middot"]="·",
+["gsiml"]="⪐",
+["biguplus"]="⨄",
+["Prime"]="″",
+["bigcirc"]="◯",
+["vsubnE"]="⫋︀",
+["lrtri"]="⊿",
+["nparallel"]="∦",
["lbbrk"]="❲",
-["rarrtl"]="↣",
-["SucceedsEqual"]="⪰",
-["HumpDownHump"]="≎",
-["Vee"]="⋁",
-["Gopf"]="𝔾",
-["otilde"]="õ",
-["ofr"]="𝔬",
-["Sub"]="⋐",
-["gnE"]="≩",
-["SquareSuperset"]="⊐",
-["leftrightharpoons"]="⇋",
-["tosa"]="⤩",
-["Ucirc"]="Û",
-["mscr"]="𝓂",
-["Exists"]="∃",
-["langle"]="⟨",
-["rfr"]="𝔯",
-["THORN"]="Þ",
-["gtreqqless"]="⪌",
-["eqvparsl"]="⧥",
-["NotCongruent"]="≢",
-["phiv"]="ϕ",
-["lsquor"]="‚",
-["prec"]="≺",
-["igrave"]="ì",
-["Fopf"]="𝔽",
-["nwArr"]="⇖",
-["nscr"]="𝓃",
-["gescc"]="⪩",
-["intprod"]="⨼",
-["larrlp"]="↫",
-["AMP"]="&",
-["psi"]="ψ",
-["mDDot"]="∺",
-["VDash"]="⊫",
-["Lleftarrow"]="⇚",
-["mfr"]="𝔪",
+["dotsquare"]="⊡",
+["rceil"]="⌉",
["gesles"]="⪔",
-["kscr"]="𝓀",
-["Omega"]="Ω",
-["bumpe"]="≏",
-["NotDoubleVerticalBar"]="∦",
-["frac18"]="⅛",
-["ecolon"]="≕",
-["compfn"]="∘",
-["supdot"]="⪾",
-["Alpha"]="Α",
-["rsquor"]="’",
+["roarr"]="⇾",
+["simplus"]="⨤",
+["lagran"]="ℒ",
+["pr"]="≺",
+["mnplus"]="∓",
+["Iota"]="Ι",
+["NestedLessLess"]="≪",
+["utilde"]="ũ",
+["mldr"]="…",
+["bigstar"]="★",
+["micro"]="µ",
["percnt"]="%",
-["pfr"]="𝔭",
-["frasl"]="⁄",
-["lscr"]="𝓁",
-["aleph"]="ℵ",
-["swArr"]="⇙",
-["uuml"]="ü",
-["uacute"]="ú",
-["scE"]="⪴",
-["hellip"]="…",
+["fllig"]="fl",
+["euml"]="ë",
+["circledR"]="®",
+["lltri"]="◺",
+["IEcy"]="Е",
+["notniva"]="∌",
+["or"]="∨",
+["curvearrowleft"]="↶",
+["gnapprox"]="⪊",
+["NotLessSlantEqual"]="⩽̸",
+["Cconint"]="∰",
+["NotSucceedsTilde"]="≿̸",
+["gammad"]="ϝ",
+["rightharpoondown"]="⇁",
+["CounterClockwiseContourIntegral"]="∳",
+["supdot"]="⪾",
+["upsi"]="υ",
+["nvle"]="≤⃒",
+["beth"]="ℶ",
+["nhArr"]="⇎",
+["Gamma"]="Γ",
+["complement"]="∁",
+["xoplus"]="⨁",
+["chi"]="χ",
+["backepsilon"]="϶",
+["nsube"]="⊈",
+["aopf"]="𝕒",
+["para"]="¶",
+["drbkarow"]="⤐",
+["Dstrok"]="Đ",
+["isinE"]="⋹",
+["Ecirc"]="Ê",
+["aelig"]="æ",
["ulcorner"]="⌜",
-["prnap"]="⪹",
-["Gg"]="⋙",
-["wedge"]="∧",
-["SquareSubset"]="⊏",
-["qscr"]="𝓆",
-["kfr"]="𝔨",
-["RightTee"]="⊢",
-["eqsim"]="≂",
-["rbrksld"]="⦎",
-["ohm"]="Ω",
-["lozf"]="⧫",
-["cups"]="∪︀",
-["epsilon"]="ε",
-["ncap"]="⩃",
-["Leftarrow"]="⇐",
-["ultri"]="◸",
-["egrave"]="è",
-["vBarv"]="⫩",
-["bNot"]="⫭",
-["nfr"]="𝔫",
-["rsqb"]="]",
-["OpenCurlyDoubleQuote"]="“",
-["rsquo"]="’",
-["Del"]="∇",
-["smtes"]="⪬︀",
-["varphi"]="ϕ",
-["CirclePlus"]="⊕",
-["prcue"]="≼",
-["curren"]="¤",
-["nltri"]="⋪",
-["oscr"]="ℴ",
-["Wcirc"]="Ŵ",
-["prime"]="′",
-["ifr"]="𝔦",
-["apos"]="'",
-["UpTee"]="⊥",
-["lescc"]="⪨",
-["NegativeMediumSpace"]="​",
-["DownTee"]="⊤",
-["NotSquareSubsetEqual"]="⋢",
-["LowerRightArrow"]="↘",
-["wr"]="≀",
+["Lcaron"]="Ľ",
+["bopf"]="𝕓",
+["midast"]="*",
+["barvee"]="⊽",
+["nvgt"]=">⃒",
+["bnequiv"]="≡⃥",
+["caron"]="ˇ",
["andand"]="⩕",
-["gvnE"]="≩︀",
-["lfr"]="𝔩",
-["lowast"]="∗",
-["gfr"]="𝔤",
-["digamma"]="ϝ",
-["cemptyv"]="⦲",
-["ubreve"]="ŭ",
-["dstrok"]="đ",
+["eparsl"]="⧣",
+["xhArr"]="⟺",
+["Yuml"]="Ÿ",
+["fallingdotseq"]="≒",
+["vltri"]="⊲",
+["gtrarr"]="⥸",
+["nGtv"]="≫̸",
+["congdot"]="⩭",
+["lfisht"]="⥼",
+["nrtri"]="⋫",
+["prnsim"]="⋨",
+["nsupE"]="⫆̸",
+["Colone"]="⩴",
+["SquareSuperset"]="⊐",
+["boxUL"]="╝",
+["Rrightarrow"]="⇛",
+["nleftrightarrow"]="↮",
+["Conint"]="∯",
+["ffilig"]="ffi",
+["nleqq"]="≦̸",
+["drcrop"]="⌌",
+["boxh"]="─",
+["Lang"]="⟪",
+["ldrdhar"]="⥧",
+["rbrack"]="]",
+["nvinfin"]="⧞",
+["succsim"]="≿",
+["boxhu"]="┴",
+["tau"]="τ",
+["incare"]="℅",
+["flat"]="♭",
+["angst"]="Å",
+["Oslash"]="Ø",
+["Vfr"]="𝔙",
+["tscy"]="ц",
+["lates"]="⪭︀",
+["eopf"]="𝕖",
+["Because"]="∵",
+["frac25"]="⅖",
+["daleth"]="ℸ",
+["ic"]="⁣",
+["ensp"]=" ",
+["lrm"]="‎",
+["DoubleLeftRightArrow"]="⇔",
+["kappa"]="κ",
+["fopf"]="𝕗",
+["cularr"]="↶",
+["shy"]="­",
+["yen"]="¥",
+["glj"]="⪤",
+["dzcy"]="џ",
["expectation"]="ℰ",
-["sime"]="≃",
-["ltrif"]="◂",
-["iacute"]="í",
-["chi"]="χ",
+["dash"]="‐",
+["female"]="♀",
+["UnderBrace"]="⏟",
+["rotimes"]="⨵",
+["caps"]="∩︀",
+["copf"]="𝕔",
+["lparlt"]="⦓",
+["NotLess"]="≮",
+["simrarr"]="⥲",
+["dtri"]="▿",
+["supne"]="⊋",
+["block"]="█",
+["siml"]="⪝",
+["blk12"]="▒",
+["natural"]="♮",
+["frac34"]="¾",
+["frac38"]="⅜",
+["Ufr"]="𝔘",
+["gg"]="≫",
+["Square"]="□",
+["lt"]="<",
["erDot"]="≓",
-["Vcy"]="В",
+["RightAngleBracket"]="⟩",
+["LeftDownTeeVector"]="⥡",
+["NotGreaterGreater"]="≫̸",
+["uogon"]="ų",
+["ocirc"]="ô",
+["sung"]="♪",
+["dollar"]="$",
+["Scaron"]="Š",
+["top"]="⊤",
+["iopf"]="𝕚",
+["udhar"]="⥮",
+["gjcy"]="ѓ",
+["ncap"]="⩃",
+["circlearrowleft"]="↺",
+["bernou"]="ℬ",
+["angmsdaf"]="⦭",
+["ldsh"]="↲",
+["isins"]="⋴",
+["RoundImplies"]="⥰",
+["bigtriangledown"]="▽",
+["LeftAngleBracket"]="⟨",
+["HorizontalLine"]="─",
+["Vdashl"]="⫦",
+["rHar"]="⥤",
+["Tcaron"]="Ť",
+["LeftDownVectorBar"]="⥙",
+["jopf"]="𝕛",
+["LeftRightVector"]="⥎",
+["LessGreater"]="≶",
+["npart"]="∂̸",
+["nsmid"]="∤",
+["RightTriangleBar"]="⧐",
+["nesim"]="≂̸",
+["deg"]="°",
+["LeftTeeArrow"]="↤",
+["NotHumpDownHump"]="≎̸",
+["tridot"]="◬",
+["lceil"]="⌈",
+["ExponentialE"]="ⅇ",
+["tosa"]="⤩",
+["gopf"]="𝕘",
+["ContourIntegral"]="∮",
+["late"]="⪭",
+["bbrk"]="⎵",
+["half"]="½",
["boxhd"]="┬",
-["DoubleDownArrow"]="⇓",
-["lArr"]="⇐",
-["demptyv"]="⦱",
-["smt"]="⪪",
-["intcal"]="⊺",
-["in"]="∈",
-["capcup"]="⩇",
-["kjcy"]="ќ",
-["Ccirc"]="Ĉ",
-["bnequiv"]="≡⃥",
-["Emacr"]="Ē",
-["siml"]="⪝",
-["jfr"]="𝔧",
-["gesdoto"]="⪂",
-["efr"]="𝔢",
-["precneqq"]="⪵",
-["because"]="∵",
-["Udblac"]="Ű",
-["lg"]="≶",
-["boxvr"]="├",
-["fpartint"]="⨍",
-["rbbrk"]="❳",
-["LT"]="<",
-["cap"]="∩",
-["circledR"]="®",
-["notinvc"]="⋶",
-["zwj"]="‍",
-["nle"]="≰",
-["hfr"]="𝔥",
-["bigsqcup"]="⨆",
-["nGg"]="⋙̸",
-["doublebarwedge"]="⌆",
+["hopf"]="𝕙",
+["Ouml"]="Ö",
+["Atilde"]="Ã",
+["planckh"]="ℎ",
+["MinusPlus"]="∓",
+["uharl"]="↿",
+["aleph"]="ℵ",
+["boxHD"]="╦",
+["lesseqgtr"]="⋚",
+["colon"]=":",
+["SquareSupersetEqual"]="⊒",
+["isinsv"]="⋳",
+["lnapprox"]="⪉",
+["PrecedesSlantEqual"]="≼",
+["boxuL"]="╛",
+["csup"]="⫐",
+["hstrok"]="ħ",
+["leftrightharpoons"]="⇋",
+["boxuR"]="╘",
+["DD"]="ⅅ",
+["Longrightarrow"]="⟹",
+["epsilon"]="ε",
+["NotTildeTilde"]="≉",
+["nfr"]="𝔫",
+["Vscr"]="𝒱",
+["Ncy"]="Н",
+["boxUl"]="╜",
+["searr"]="↘",
+["ddagger"]="‡",
+["KHcy"]="Х",
+["NotSuperset"]="⊃⃒",
+["Uparrow"]="⇑",
+["nsqsube"]="⋢",
+["Imacr"]="Ī",
+["nspar"]="∦",
+["supsetneqq"]="⫌",
+["Sscr"]="𝒮",
+["lobrk"]="⟦",
+["mfr"]="𝔪",
+["acirc"]="â",
+["subne"]="⊊",
+["Icirc"]="Î",
+["Re"]="ℜ",
+["nearrow"]="↗",
["YUcy"]="Ю",
-["empty"]="∅",
-["nacute"]="ń",
-["Acirc"]="Â",
-["bigtriangleup"]="△",
-["hybull"]="⁃",
-["Ycy"]="Ы",
-["isindot"]="⋵",
-["iota"]="ι",
-["numero"]="№",
-["cfr"]="𝔠",
-["llarr"]="⇇",
-["lrhard"]="⥭",
-["cross"]="✗",
+["eqsim"]="≂",
+["UnionPlus"]="⊎",
+["topcir"]="⫱",
+["boxVL"]="╣",
+["Xscr"]="𝒳",
+["QUOT"]="\"",
+["RightDownVectorBar"]="⥕",
+["epsi"]="ε",
+["natur"]="♮",
+["leftthreetimes"]="⋋",
+["hercon"]="⊹",
+["lHar"]="⥢",
+["Aring"]="Å",
+["Kcedil"]="Ķ",
+["kfr"]="𝔨",
+["Oacute"]="Ó",
["zwnj"]="‌",
+["plusdu"]="⨥",
+["Kcy"]="К",
+["sqcup"]="⊔",
+["zscr"]="𝓏",
+["Assign"]="≔",
+["zopf"]="𝕫",
+["lstrok"]="ł",
+["zigrarr"]="⇝",
+["ShortDownArrow"]="↓",
+["simlE"]="⪟",
+["mid"]="∣",
["zeta"]="ζ",
-["precnsim"]="⋨",
-["zcy"]="з",
+["gE"]="≧",
+["zeetrf"]="ℨ",
+["qfr"]="𝔮",
["zcaron"]="ž",
-["xodot"]="⨀",
-["RightDownTeeVector"]="⥝",
-["ljcy"]="љ",
+["Yacute"]="Ý",
+["hksearow"]="⤥",
+["Atilde"]="Ã",
+["zacute"]="ź",
+["bsemi"]="⁏",
+["bigtriangleup"]="△",
+["yuml"]="ÿ",
+["yucy"]="ю",
["yscr"]="𝓎",
+["yopf"]="𝕪",
["yicy"]="ї",
-["Rcy"]="Р",
-["nsubset"]="⊂⃒",
-["yen"]="¥",
-["ycy"]="ы",
-["simeq"]="≃",
-["dharr"]="⇂",
-["ycirc"]="ŷ",
-["hArr"]="⇔",
-["yacute"]="ý",
-["yacute"]="ý",
+["urcorn"]="⌝",
+["Aacute"]="Á",
+["backsimeq"]="⋍",
+["ShortUpArrow"]="↑",
["xwedge"]="⋀",
-["xoplus"]="⨁",
-["nparsl"]="⫽⃥",
-["PartialD"]="∂",
-["YAcy"]="Я",
-["xrArr"]="⟹",
-["xotime"]="⨂",
-["sstarf"]="⋆",
-["yuml"]="ÿ",
-["Int"]="∬",
-["bsolb"]="⧅",
+["Jcy"]="Й",
+["nltrie"]="⋬",
+["starf"]="★",
+["zfr"]="𝔷",
+["comma"]=",",
+["xsqcup"]="⨆",
+["boxVr"]="╟",
+["cirscir"]="⧂",
+["ucirc"]="û",
+["Cross"]="⨯",
+["naturals"]="ℕ",
+["quaternions"]="ℍ",
+["xopf"]="𝕩",
+["xodot"]="⨀",
["xnis"]="⋻",
-["xmap"]="⟼",
-["hercon"]="⊹",
-["xlArr"]="⟸",
-["xharr"]="⟷",
-["rbrack"]="]",
+["lsaquo"]="‹",
+["xlarr"]="⟵",
+["Zacute"]="Ź",
+["vdash"]="⊢",
+["submult"]="⫁",
+["Oscr"]="𝒪",
["xdtri"]="▽",
-["diamond"]="⋄",
+["LowerRightArrow"]="↘",
["xcup"]="⋃",
-["subsup"]="⫓",
-["lneqq"]="≨",
-["dharl"]="⇃",
-["Scy"]="С",
-["wopf"]="𝕨",
-["rightleftharpoons"]="⇌",
-["wfr"]="𝔴",
-["nsupseteqq"]="⫆̸",
-["boxuR"]="╘",
-["permil"]="‰",
+["Ycy"]="Ы",
+["timesb"]="⊠",
+["Ucirc"]="Û",
+["eth"]="ð",
+["wscr"]="𝓌",
+["ratail"]="⤚",
+["wr"]="≀",
+["Ograve"]="Ò",
+["wp"]="℘",
+["euml"]="ë",
+["yfr"]="𝔶",
+["rangle"]="⟩",
+["hearts"]="♥",
["wedgeq"]="≙",
-["eparsl"]="⧣",
-["RoundImplies"]="⥰",
-["afr"]="𝔞",
-["vsubne"]="⊊︀",
-["sup2"]="²",
+["wedge"]="∧",
+["gtcir"]="⩺",
+["par"]="∥",
+["swarr"]="↙",
+["phiv"]="ϕ",
+["NotElement"]="∉",
+["alpha"]="α",
+["SquareUnion"]="⊔",
+["parsl"]="⫽",
["vscr"]="𝓋",
+["rharu"]="⇀",
+["vrtri"]="⊳",
+["comp"]="∁",
+["Agrave"]="À",
+["rdca"]="⤷",
+["vprop"]="∝",
+["Tscr"]="𝒯",
["vopf"]="𝕧",
-["lbrace"]="{",
+["ldca"]="⤶",
["vnsub"]="⊂⃒",
-["vltri"]="⊲",
-["Uacute"]="Ú",
-["vfr"]="𝔳",
-["sacute"]="ś",
-["njcy"]="њ",
-["frac35"]="⅗",
-["squf"]="▪",
+["gbreve"]="ğ",
+["NotSquareSubset"]="⊏̸",
+["verbar"]="|",
+["YAcy"]="Я",
["veeeq"]="≚",
-["lsime"]="⪍",
-["mapstoleft"]="↤",
+["downharpoonleft"]="⇃",
+["Star"]="⋆",
+["xfr"]="𝔵",
+["nges"]="⩾̸",
+["GreaterGreater"]="⪢",
+["vartriangleright"]="⊳",
+["rcy"]="р",
+["vartheta"]="ϑ",
+["varsupsetneqq"]="⫌︀",
+["dashv"]="⊣",
["varsupsetneq"]="⊋︀",
-["varsubsetneq"]="⊊︀",
-["Tcy"]="Т",
-["cwint"]="∱",
-["varsigma"]="ς",
-["LessGreater"]="≶",
+["Ncaron"]="Ň",
+["varsubsetneqq"]="⫋︀",
["varrho"]="ϱ",
-["varpropto"]="∝",
-["pr"]="≺",
-["backprime"]="‵",
+["triangledown"]="▿",
+["varpi"]="ϖ",
+["sol"]="/",
+["ssetmn"]="∖",
+["varnothing"]="∅",
["varkappa"]="ϰ",
-["Poincareplane"]="ℌ",
-["roplus"]="⨮",
-["Edot"]="Ė",
-["copysr"]="℗",
+["vangrt"]="⦜",
+["Leftarrow"]="⇐",
+["Qscr"]="𝒬",
+["uwangle"]="⦧",
+["rarrap"]="⥵",
["uuml"]="ü",
-["dfr"]="𝔡",
["uuarr"]="⇈",
-["uogon"]="ų",
-["Uscr"]="𝒰",
-["gel"]="⋛",
-["olarr"]="↺",
-["lsaquo"]="‹",
-["omacr"]="ō",
-["utdot"]="⋰",
-["or"]="∨",
-["Ocirc"]="Ô",
-["ClockwiseContourIntegral"]="∲",
-["SmallCircle"]="∘",
-["gtcc"]="⪧",
["uscr"]="𝓊",
+["urtri"]="◹",
+["uring"]="ů",
+["sect"]="§",
+["quatint"]="⨖",
["urcrop"]="⌎",
-["ContourIntegral"]="∮",
-["szlig"]="ß",
-["egs"]="⪖",
-["Ucy"]="У",
-["ange"]="⦤",
-["upharpoonright"]="↾",
-["xcap"]="⋂",
+["wfr"]="𝔴",
+["duhar"]="⥯",
+["upuparrows"]="⇈",
+["macr"]="¯",
+["SmallCircle"]="∘",
+["upsih"]="ϒ",
+["uplus"]="⊎",
+["shy"]="­",
+["uparrow"]="↑",
["uml"]="¨",
-["nsubseteqq"]="⫅̸",
+["eDot"]="≑",
+["blk34"]="▓",
+["umacr"]="ū",
+["ultri"]="◸",
+["rbbrk"]="❳",
["ulcorn"]="⌜",
-["uhblk"]="▀",
-["scirc"]="ŝ",
-["shy"]="­",
-["uharl"]="↿",
+["uharr"]="↾",
["ugrave"]="ù",
-["lstrok"]="ł",
-["Gamma"]="Γ",
-["udhar"]="⥮",
-["udblac"]="ű",
-["ucirc"]="û",
-["loang"]="⟬",
-["uarr"]="↑",
+["Ograve"]="Ò",
+["nsupseteq"]="⊉",
+["ufisht"]="⥾",
+["Breve"]="˘",
+["ucy"]="у",
+["cylcty"]="⌭",
+["ubreve"]="ŭ",
+["SHcy"]="Ш",
+["boxdR"]="╒",
+["awint"]="⨑",
+["uHar"]="⥣",
["uArr"]="⇑",
-["twoheadrightarrow"]="↠",
+["REG"]="®",
+["twoheadleftarrow"]="↞",
["tstrok"]="ŧ",
+["iprod"]="⨼",
["tshcy"]="ћ",
-["tscy"]="ц",
-["angsph"]="∢",
-["kappa"]="κ",
["tscr"]="𝓉",
-["tritime"]="⨻",
-["trisb"]="⧍",
+["trpezium"]="⏢",
+["ycirc"]="ŷ",
+["larrhk"]="↩",
+["triplus"]="⨹",
["triminus"]="⨺",
-["trie"]="≜",
-["tridot"]="◬",
-["aacute"]="á",
+["Rsh"]="↱",
+["becaus"]="∵",
+["Acirc"]="Â",
["trianglerighteq"]="⊵",
-["RightTeeVector"]="⥛",
["triangleright"]="▹",
+["hkswarow"]="⤦",
+["triangleq"]="≜",
+["AElig"]="Æ",
["trianglelefteq"]="⊴",
+["varpropto"]="∝",
["triangle"]="▵",
-["NegativeVeryThinSpace"]="​",
-["triangledown"]="▿",
-["dash"]="‐",
-["trade"]="™",
+["tprime"]="‴",
["topfork"]="⫚",
-["Upsi"]="ϒ",
-["topcir"]="⫱",
-["loplus"]="⨭",
-["Zdot"]="Ż",
-["lbrke"]="⦋",
-["angmsd"]="∡",
-["dArr"]="⇓",
-["topbot"]="⌶",
["toea"]="⤨",
-["iexcl"]="¡",
-["acirc"]="â",
-["easter"]="⩮",
-["CloseCurlyDoubleQuote"]="”",
-["cupcup"]="⩊",
-["rlhar"]="⇌",
-["nsimeq"]="≄",
-["Uparrow"]="⇑",
-["tau"]="τ",
-["npr"]="⊀",
-["phone"]="☎",
-["emacr"]="ē",
-["SHcy"]="Ш",
-["gtdot"]="⋗",
-["ReverseUpEquilibrium"]="⥯",
+["ac"]="∾",
+["timesd"]="⨰",
+["UpArrowDownArrow"]="⇅",
+["timesbar"]="⨱",
+["llhard"]="⥫",
+["CHcy"]="Ч",
+["odblac"]="ő",
+["THORN"]="Þ",
+["notni"]="∌",
+["nbump"]="≎̸",
+["eqcolon"]="≕",
["tilde"]="˜",
-["angmsdac"]="⦪",
-["duhar"]="⥯",
-["approxeq"]="≊",
-["NotSupersetEqual"]="⊉",
-["thorn"]="þ",
-["thksim"]="∼",
-["subsim"]="⫇",
-["bnot"]="⌐",
+["simgE"]="⪠",
+["intercal"]="⊺",
+["thetasym"]="ϑ",
+["xcirc"]="◯",
["thinsp"]=" ",
["thicksim"]="∼",
-["gt"]=">",
-["UpperLeftArrow"]="↖",
-["thetasym"]="ϑ",
-["simlE"]="⪟",
-["bbrktbrk"]="⎶",
-["Jcirc"]="Ĵ",
-["cedil"]="¸",
-["NotLessSlantEqual"]="⩽̸",
-["rx"]="℞",
-["infin"]="∞",
-["curlyvee"]="⋎",
-["LeftArrow"]="←",
-["tfr"]="𝔱",
-["blacksquare"]="▪",
-["emptyv"]="∅",
-["Mellintrf"]="ℳ",
-["aogon"]="ą",
-["succnapprox"]="⪺",
-["tcy"]="т",
-["ecaron"]="ě",
+["LeftArrowBar"]="⇤",
+["Uuml"]="Ü",
+["DownTeeArrow"]="↧",
+["cent"]="¢",
+["hookleftarrow"]="↩",
+["odiv"]="⨸",
+["therefore"]="∴",
+["ClockwiseContourIntegral"]="∲",
+["Ofr"]="𝔒",
+["auml"]="ä",
+["frac12"]="½",
+["nRightarrow"]="⇏",
+["kcedil"]="ķ",
+["DownRightVectorBar"]="⥗",
+["boxDL"]="╗",
["tcedil"]="ţ",
-["boxhU"]="╨",
-["boxVl"]="╢",
-["gacute"]="ǵ",
-["tcaron"]="ť",
-["boxDr"]="╓",
-["bump"]="≎",
-["blk12"]="▒",
-["RightArrow"]="→",
-["els"]="⪕",
-["apacir"]="⩯",
-["acy"]="а",
-["omid"]="⦶",
-["boxbox"]="⧉",
-["iecy"]="е",
-["szlig"]="ß",
-["upsih"]="ϒ",
-["swnwar"]="⤪",
-["Icirc"]="Î",
-["swarr"]="↙",
-["times"]="×",
-["Ograve"]="Ò",
-["hoarr"]="⇿",
-["NotTildeEqual"]="≄",
-["IEcy"]="Е",
-["iexcl"]="¡",
-["bdquo"]="„",
-["TildeTilde"]="≈",
+["boxUr"]="╙",
+["icirc"]="î",
+["lmoustache"]="⎰",
+["prime"]="′",
+["ngeq"]="≱",
["nshortparallel"]="∦",
-["subedot"]="⫃",
-["supsetneq"]="⊋",
-["CenterDot"]="·",
-["lessapprox"]="⪅",
-["LeftVectorBar"]="⥒",
-["bigoplus"]="⨁",
-["supseteqq"]="⫆",
-["drcorn"]="⌟",
-["hstrok"]="ħ",
-["HorizontalLine"]="─",
-["curarrm"]="⤼",
-["lopar"]="⦅",
+["szlig"]="ß",
+["Egrave"]="È",
+["sqsubset"]="⊏",
+["NotRightTriangleEqual"]="⋭",
+["swarrow"]="↙",
+["Ucirc"]="Û",
+["DownArrowBar"]="⤓",
+["Lfr"]="𝔏",
["wcirc"]="ŵ",
+["LessLess"]="⪡",
+["Tilde"]="∼",
+["empty"]="∅",
+["swarhk"]="⤦",
+["DownLeftVector"]="↽",
+["Uscr"]="𝒰",
+["khcy"]="х",
+["gesl"]="⋛︀",
+["supsub"]="⫔",
+["malt"]="✠",
+["cirmid"]="⫯",
+["PrecedesTilde"]="≾",
+["lharul"]="⥪",
+["rightleftharpoons"]="⇌",
+["Ccedil"]="Ç",
+["plusb"]="⊞",
+["nsupe"]="⊉",
+["geq"]="≥",
+["dHar"]="⥥",
+["lcedil"]="ļ",
+["ange"]="⦤",
+["supseteq"]="⊇",
+["Upsi"]="ϒ",
+["mapstodown"]="↧",
+["profalar"]="⌮",
+["cupdot"]="⊍",
+["mapstoleft"]="↤",
+["xotime"]="⨂",
+["tbrk"]="⎴",
+["supmult"]="⫂",
+["disin"]="⋲",
["suphsub"]="⫗",
-["Otilde"]="Õ",
-["EmptySmallSquare"]="◻",
+["eg"]="⪚",
["supedot"]="⫄",
-["Kopf"]="𝕂",
-["boxminus"]="⊟",
-["csupe"]="⫒",
-["Ffr"]="𝔉",
-["origof"]="⊶",
-["sup3"]="³",
-["boxH"]="═",
-["vsubnE"]="⫋︀",
-["Hcirc"]="Ĥ",
-["block"]="█",
+["NonBreakingSpace"]=" ",
+["Euml"]="Ë",
["bsolhsub"]="⟈",
-["Supset"]="⋑",
-["GreaterFullEqual"]="≧",
+["supdsub"]="⫘",
+["sup3"]="³",
+["DoubleLeftTee"]="⫤",
+["angrtvb"]="⊾",
+["supsim"]="⫈",
+["sup2"]="²",
+["sup2"]="²",
+["circledast"]="⊛",
+["rfr"]="𝔯",
+["darr"]="↓",
+["rarrhk"]="↪",
+["macr"]="¯",
["sup1"]="¹",
-["llcorner"]="⌞",
-["sopf"]="𝕤",
-["larrbfs"]="⤟",
-["succneqq"]="⪶",
-["part"]="∂",
-["eacute"]="é",
-["COPY"]="©",
-["frac23"]="⅔",
-["dbkarow"]="⤏",
-["succeq"]="⪰",
-["notni"]="∌",
-["Euml"]="Ë",
-["harrcir"]="⥈",
-["leftrightsquigarrow"]="↭",
-["xcirc"]="◯",
-["caret"]="⁁",
-["les"]="⩽",
-["lharul"]="⥪",
-["bsime"]="⋍",
-["DoubleLeftArrow"]="⇐",
-["ecirc"]="ê",
-["subsetneqq"]="⫋",
-["crarr"]="↵",
-["cuwed"]="⋏",
-["Ugrave"]="Ù",
-["Gcirc"]="Ĝ",
-["LeftTriangleBar"]="⧏",
+["aacute"]="á",
+["oscr"]="ℴ",
+["lharu"]="↼",
+["telrec"]="⌕",
+["Dashv"]="⫤",
+["succnsim"]="⋩",
+["AElig"]="Æ",
+["Vee"]="⋁",
+["succnapprox"]="⪺",
+["CapitalDifferentialD"]="ⅅ",
["gsim"]="≳",
-["RightTriangleEqual"]="⊵",
-["lacute"]="ĺ",
-["Ccedil"]="Ç",
-["ee"]="ⅇ",
-["heartsuit"]="♥",
-["coloneq"]="≔",
-["subseteq"]="⊆",
-["NotSucceedsTilde"]="≿̸",
+["succapprox"]="⪸",
+["rmoustache"]="⎱",
+["DotEqual"]="≐",
+["subsup"]="⫓",
+["Gcedil"]="Ģ",
+["questeq"]="≟",
+["lthree"]="⋋",
+["cong"]="≅",
+["lcub"]="{",
+["radic"]="√",
+["subrarr"]="⥹",
+["nvlt"]="<⃒",
["subplus"]="⪿",
-["cupcap"]="⩆",
-["Amacr"]="Ā",
-["angst"]="Å",
-["supsetneqq"]="⫌",
-["sube"]="⊆",
-["imagpart"]="ℑ",
-["Lambda"]="Λ",
-["Afr"]="𝔄",
-["sub"]="⊂",
+["bigsqcup"]="⨆",
+["downarrow"]="↓",
+["auml"]="ä",
+["boxdL"]="╕",
+["boxvr"]="├",
+["lbrkslu"]="⦍",
+["bigwedge"]="⋀",
+["apacir"]="⩯",
+["Wscr"]="𝒲",
+["iecy"]="е",
+["VerticalSeparator"]="❘",
+["Yfr"]="𝔜",
["strns"]="¯",
["straightphi"]="ϕ",
-["boxvL"]="╡",
-["dagger"]="†",
-["eta"]="η",
-["KHcy"]="Х",
-["Yfr"]="𝔜",
-["lbrack"]="[",
-["VerticalBar"]="∣",
-["rightleftarrows"]="⇄",
-["fltns"]="▱",
-["verbar"]="|",
-["RightAngleBracket"]="⟩",
-["DownRightVector"]="⇁",
-["Lacute"]="Ĺ",
-["sol"]="/",
-["lrm"]="‎",
-["lesdot"]="⩿",
-["nleqslant"]="⩽̸",
-["capcap"]="⩋",
+["kcy"]="к",
+["aogon"]="ą",
+["star"]="☆",
+["caret"]="⁁",
+["cups"]="∪︀",
+["iquest"]="¿",
+["spar"]="∥",
+["NotExists"]="∄",
+["Gt"]="≫",
["squ"]="□",
-["xutri"]="△",
-["TSHcy"]="Ћ",
-["gap"]="⪆",
-["gtrdot"]="⋗",
-["scnap"]="⪺",
-["bkarow"]="⤍",
-["NotPrecedes"]="⊀",
-["suphsol"]="⟉",
+["sqsupe"]="⊒",
+["subnE"]="⫋",
["sqsup"]="⊐",
-["epsi"]="ε",
-["sqsubset"]="⊏",
-["check"]="✓",
-["UpArrowBar"]="⤒",
-["NotPrecedesEqual"]="⪯̸",
-["csube"]="⫑",
-["nsupset"]="⊃⃒",
-["lesdoto"]="⪁",
+["sqsubseteq"]="⊑",
+["ffr"]="𝔣",
+["UpTeeArrow"]="↥",
+["middot"]="·",
+["DoubleLongRightArrow"]="⟹",
+["sqsube"]="⊑",
+["sce"]="⪰",
+["Sup"]="⋑",
+["cacute"]="ć",
+["GreaterFullEqual"]="≧",
+["pfr"]="𝔭",
+["Lleftarrow"]="⇚",
+["heartsuit"]="♥",
+["precsim"]="≾",
+["nsucceq"]="⪰̸",
["sqcups"]="⊔︀",
-["suplarr"]="⥻",
-["nsim"]="≁",
-["NotEqualTilde"]="≂̸",
-["nearr"]="↗",
-["SquareIntersection"]="⊓",
-["intlarhk"]="⨗",
-["Ecirc"]="Ê",
-["vangrt"]="⦜",
-["fllig"]="fl",
-["Leftrightarrow"]="⇔",
-["primes"]="ℙ",
-["nvlArr"]="⤂",
+["Igrave"]="Ì",
+["iquest"]="¿",
+["Pcy"]="П",
+["thksim"]="∼",
+["djcy"]="ђ",
+["hfr"]="𝔥",
+["spadesuit"]="♠",
+["rbrkslu"]="⦐",
+["shcy"]="ш",
+["barwed"]="⌅",
+["rpar"]=")",
+["iiiint"]="⨌",
+["solb"]="⧄",
+["Integral"]="∫",
+["napE"]="⩰̸",
+["softcy"]="ь",
+["NotRightTriangleBar"]="⧐̸",
+["Mu"]="Μ",
+["frasl"]="⁄",
+["Icy"]="И",
+["dfisht"]="⥿",
["smte"]="⪬",
-["ltri"]="◃",
-["Tscr"]="𝒯",
+["smt"]="⪪",
+["bottom"]="⊥",
+["oacute"]="ó",
+["ofr"]="𝔬",
["smid"]="∣",
-["smeparsl"]="⧤",
-["rarrc"]="⤳",
-["divideontimes"]="⋇",
-["eth"]="ð",
-["boxvR"]="╞",
-["copy"]="©",
-["nges"]="⩾̸",
-["fcy"]="ф",
-["ShortUpArrow"]="↑",
-["simplus"]="⨤",
-["frac45"]="⅘",
-["nexists"]="∄",
-["LeftTeeArrow"]="↤",
-["leftleftarrows"]="⇇",
-["simg"]="⪞",
-["euro"]="€",
-["simdot"]="⩪",
-["sim"]="∼",
-["sigmav"]="ς",
-["iuml"]="ï",
-["updownarrow"]="↕",
-["shy"]="­",
-["solb"]="⧄",
+["ReverseUpEquilibrium"]="⥯",
+["smashp"]="⨳",
+["slarr"]="←",
+["simne"]="≆",
+["LeftRightArrow"]="↔",
+["thkap"]="≈",
+["nlArr"]="⇍",
+["chcy"]="ч",
+["not"]="¬",
+["kgreen"]="ĸ",
+["simeq"]="≃",
+["LongRightArrow"]="⟶",
+["sime"]="≃",
+["sigma"]="σ",
+["odot"]="⊙",
+["amp"]="&",
+["Longleftrightarrow"]="⟺",
+["Upsilon"]="Υ",
+["upharpoonleft"]="↿",
+["bigotimes"]="⨂",
+["parallel"]="∥",
+["ffllig"]="ffl",
+["shortparallel"]="∥",
+["boxdr"]="┌",
+["shortmid"]="∣",
+["Euml"]="Ë",
+["UpDownArrow"]="↕",
+["lcaron"]="ľ",
+["sfrown"]="⌢",
+["harr"]="↔",
+["dsol"]="⧶",
+["Beta"]="Β",
+["srarr"]="→",
+["boxHd"]="╤",
["nesear"]="⤨",
-["Umacr"]="Ū",
-["uharr"]="↾",
-["Therefore"]="∴",
-["Barv"]="⫧",
-["amacr"]="ā",
["setmn"]="∖",
+["DoubleDot"]="¨",
["setminus"]="∖",
-["Sscr"]="𝒮",
+["andd"]="⩜",
+["leftrightarrow"]="↔",
["seswar"]="⤩",
-["ccupssm"]="⩐",
-["searr"]="↘",
+["eogon"]="ę",
+["bne"]="=⃥",
+["DownBreve"]="̑",
+["nLtv"]="≪̸",
+["nprcue"]="⋠",
+["SucceedsSlantEqual"]="≽",
+["downdownarrows"]="⇊",
+["seArr"]="⇘",
+["Utilde"]="Ũ",
+["Gammad"]="Ϝ",
+["sdote"]="⩦",
+["iexcl"]="¡",
+["nvdash"]="⊬",
+["csupe"]="⫒",
["sdotb"]="⊡",
-["icirc"]="î",
-["amp"]="&",
-["gcy"]="г",
-["Aacute"]="Á",
-["boxvh"]="┼",
-["bfr"]="𝔟",
-["OverParenthesis"]="⏜",
-["sqsupe"]="⊒",
-["amp"]="&",
-["frac14"]="¼",
-["ZeroWidthSpace"]="​",
-["Colon"]="∷",
-["Proportional"]="∝",
-["thickapprox"]="≈",
-["subseteqq"]="⫅",
-["IJlig"]="IJ",
-["scedil"]="ş",
-["lrarr"]="⇆",
-["angmsdaf"]="⦭",
-["downharpoonleft"]="⇃",
+["scsim"]="≿",
+["bcy"]="б",
+["NotTilde"]="≁",
+["minus"]="−",
+["scnE"]="⪶",
+["scirc"]="ŝ",
+["oplus"]="⊕",
+["para"]="¶",
+["Ycirc"]="Ŷ",
+["notinva"]="∉",
+["nLl"]="⋘̸",
+["Aring"]="Å",
+["THORN"]="Þ",
+["numero"]="№",
+["scaron"]="š",
+["bsol"]="\\",
+["harrw"]="↭",
+["exponentiale"]="ⅇ",
+["eDDot"]="⩷",
+["AMP"]="&",
+["gamma"]="γ",
+["opar"]="⦷",
+["cwint"]="∱",
+["GreaterEqual"]="≥",
+["bigcap"]="⋂",
+["rtimes"]="⋊",
+["integers"]="ℤ",
+["easter"]="⩮",
["RightDoubleBracket"]="⟧",
-["half"]="½",
-["larr"]="←",
["sbquo"]="‚",
-["Vscr"]="𝒱",
-["nVdash"]="⊮",
-["DownRightVectorBar"]="⥗",
-["RightDownVector"]="⇂",
-["disin"]="⋲",
-["nsce"]="⪰̸",
-["rbrace"]="}",
-["MinusPlus"]="∓",
-["rtrif"]="▸",
-["parsim"]="⫳",
-["supseteq"]="⊇",
-["Superset"]="⊃",
-["Verbar"]="‖",
+["cfr"]="𝔠",
+["ruluhar"]="⥨",
+["image"]="ℑ",
+["nleqslant"]="⩽̸",
+["Yopf"]="𝕐",
+["apE"]="⩰",
+["NotPrecedesEqual"]="⪯̸",
+["rsqb"]="]",
+["rtrie"]="⊵",
+["rthree"]="⋌",
+["amp"]="&",
+["eng"]="ŋ",
+["ll"]="≪",
+["rrarr"]="⇉",
+["RightTee"]="⊢",
+["ETH"]="Ð",
+["ReverseEquilibrium"]="⇋",
+["langle"]="⟨",
["Zeta"]="Ζ",
-["nsccue"]="⋡",
-["bsemi"]="⁏",
-["ldquor"]="„",
-["curarr"]="↷",
-["rscr"]="𝓇",
-["rppolint"]="⨒",
-["rpargt"]="⦔",
-["rotimes"]="⨵",
-["Equal"]="⩵",
-["ropf"]="𝕣",
-["ropar"]="⦆",
-["roarr"]="⇾",
-["odot"]="⊙",
-["natural"]="♮",
-["slarr"]="←",
-["angmsdae"]="⦬",
-["acE"]="∾̳",
+["roplus"]="⨮",
+["there4"]="∴",
+["DownRightTeeVector"]="⥟",
+["npar"]="∦",
+["robrk"]="⟧",
+["exist"]="∃",
+["lfr"]="𝔩",
+["VDash"]="⊫",
+["rnmid"]="⫮",
+["rmoust"]="⎱",
["rlm"]="‏",
-["COPY"]="©",
-["iogon"]="į",
-["nleftrightarrow"]="↮",
-["reg"]="®",
-["risingdotseq"]="≓",
-["rightsquigarrow"]="↝",
-["dtri"]="▿",
-["Larr"]="↞",
-["icy"]="и",
-["gimel"]="ℷ",
+["Ccirc"]="Ĉ",
+["imagpart"]="ℑ",
+["Equilibrium"]="⇌",
+["dd"]="ⅆ",
+["cuepr"]="⋞",
+["Agrave"]="À",
+["cuesc"]="⋟",
+["square"]="□",
+["notnivc"]="⋽",
+["rbrksld"]="⦎",
["cup"]="∪",
-["DJcy"]="Ђ",
-["gtrapprox"]="⪆",
-["rightharpoonup"]="⇀",
-["prsim"]="≾",
-["rightharpoondown"]="⇁",
-["frac16"]="⅙",
-["nbsp"]=" ",
-["cedil"]="¸",
-["numsp"]=" ",
+["OpenCurlyDoubleQuote"]="“",
+["Lacute"]="Ĺ",
+["NewLine"]="\n",
+["Sigma"]="Σ",
+["Abreve"]="Ă",
+["rightleftarrows"]="⇄",
+["tint"]="∭",
+["angmsdae"]="⦬",
+["Leftrightarrow"]="⇔",
+["rdquor"]="”",
+["Verbar"]="‖",
+["Gfr"]="𝔊",
["rightarrow"]="→",
["rhov"]="ϱ",
-["rdquo"]="”",
-["rharul"]="⥬",
-["frac34"]="¾",
-["ldrdhar"]="⥧",
-["gnsim"]="⋧",
-["rtriltri"]="⧎",
-["emsp"]=" ",
-["rlarr"]="⇄",
-["Oslash"]="Ø",
-["LeftDownTeeVector"]="⥡",
+["Alpha"]="Α",
+["rho"]="ρ",
+["DownLeftTeeVector"]="⥞",
+["ntriangleright"]="⋫",
["reg"]="®",
-["LeftTeeVector"]="⥚",
-["gsiml"]="⪐",
-["QUOT"]="\"",
-["blk14"]="░",
-["rightrightarrows"]="⇉",
-["NotGreaterGreater"]="≫̸",
-["Xscr"]="𝒳",
-["Re"]="ℜ",
-["Ouml"]="Ö",
+["Int"]="∬",
+["agrave"]="à",
+["Ecirc"]="Ê",
+["NotReverseElement"]="∌",
+["backprime"]="‵",
+["Jfr"]="𝔍",
["rdsh"]="↳",
-["and"]="∧",
-["larrb"]="⇤",
-["TripleDot"]="⃛",
-["bcy"]="б",
-["diams"]="♦",
-["veebar"]="⊻",
-["rcub"]="}",
-["Scirc"]="Ŝ",
-["ac"]="∾",
-["rceil"]="⌉",
-["rcedil"]="ŗ",
-["cupbrcap"]="⩈",
-["rcaron"]="ř",
-["cuesc"]="⋟",
-["HilbertSpace"]="ℋ",
-["plus"]="+",
-["rbrkslu"]="⦐",
-["LessLess"]="⪡",
-["macr"]="¯",
-["notinE"]="⋹̸",
+["jsercy"]="ј",
+["Bscr"]="ℬ",
+["boxH"]="═",
+["leq"]="≤",
+["NotPrecedes"]="⊀",
+["coloneq"]="≔",
+["boxvh"]="┼",
+["larr"]="←",
+["ncup"]="⩂",
+["EmptySmallSquare"]="◻",
+["vartriangleleft"]="⊲",
+["iacute"]="í",
+["nVDash"]="⊯",
+["lap"]="⪅",
+["precapprox"]="⪷",
+["ecolon"]="≕",
+["lsqb"]="[",
["rbarr"]="⤍",
-["abreve"]="ă",
-["sqcup"]="⊔",
-["ratail"]="⤚",
-["VeryThinSpace"]=" ",
-["Uarrocir"]="⥉",
-["rarrfs"]="⤞",
-["Odblac"]="Ő",
-["Imacr"]="Ī",
-["ordm"]="º",
-["odsold"]="⦼",
-["NJcy"]="Њ",
-["Yacute"]="Ý",
-["rarrbfs"]="⤠",
-["prop"]="∝",
-["notin"]="∉",
-["vsupne"]="⊋︀",
-["bigcap"]="⋂",
-["Phi"]="Φ",
-["Ograve"]="Ò",
-["Yscr"]="𝒴",
-["approx"]="≈",
-["racute"]="ŕ",
-["ggg"]="⋙",
-["lmoust"]="⎰",
+["yacy"]="я",
+["efDot"]="≒",
+["ratio"]="∶",
+["wreath"]="≀",
+["nearhk"]="⤤",
+["rarrpl"]="⥅",
+["nvge"]="≥⃒",
+["searrow"]="↘",
+["thorn"]="þ",
+["rdquo"]="”",
+["LessFullEqual"]="≦",
+["nvrtrie"]="⊵⃒",
+["nsubseteqq"]="⫅̸",
+["nedot"]="≐̸",
+["VerticalLine"]="|",
+["lsh"]="↰",
+["DownRightVector"]="⇁",
+["ecirc"]="ê",
+["andv"]="⩚",
+["trie"]="≜",
+["race"]="∽̱",
["rBarr"]="⤏",
-["gneqq"]="≩",
-["isinv"]="∈",
-["harr"]="↔",
-["rArr"]="⇒",
-["rAarr"]="⇛",
-["quot"]="\"",
+["lbrksld"]="⦏",
+["emsp14"]=" ",
+["RuleDelayed"]="⧴",
+["vsubne"]="⊊︀",
+["ShortLeftArrow"]="←",
+["gtlPar"]="⦕",
["quest"]="?",
-["iuml"]="ï",
-["LeftRightArrow"]="↔",
-["LeftDoubleBracket"]="⟦",
-["gesdot"]="⪀",
-["Ntilde"]="Ñ",
-["boxUR"]="╚",
-["exist"]="∃",
-["subnE"]="⫋",
-["ograve"]="ò",
-["qopf"]="𝕢",
-["Zacute"]="Ź",
-["qfr"]="𝔮",
-["dcy"]="д",
-["NotReverseElement"]="∌",
-["DotEqual"]="≐",
-["VerticalLine"]="|",
-["pscr"]="𝓅",
-["prurel"]="⊰",
-["cdot"]="ċ",
-["bprime"]="‵",
-["ltdot"]="⋖",
-["prnsim"]="⋨",
-["curlywedge"]="⋏",
-["prnE"]="⪵",
-["REG"]="®",
-["sup3"]="³",
+["dot"]="˙",
+["RightVector"]="⇀",
+["rppolint"]="⨒",
+["Hat"]="^",
+["zcy"]="з",
+["suplarr"]="⥻",
+["boxhU"]="╨",
+["puncsp"]=" ",
+["GreaterLess"]="≷",
+["psi"]="ψ",
+["ncaron"]="ň",
+["SupersetEqual"]="⊇",
+["propto"]="∝",
["preceq"]="⪯",
-["LeftDownVectorBar"]="⥙",
-["ForAll"]="∀",
+["frac56"]="⅚",
+["NotLessGreater"]="≸",
+["jukcy"]="є",
+["swArr"]="⇙",
+["profline"]="⌒",
+["prnE"]="⪵",
+["larrpl"]="⤹",
+["af"]="⁡",
+["profsurf"]="⌓",
+["Larr"]="↞",
["forkv"]="⫙",
-["varpi"]="ϖ",
-["nrArr"]="⇏",
+["prcue"]="≼",
+["RightUpTeeVector"]="⥜",
["pound"]="£",
+["ugrave"]="ù",
+["popf"]="𝕡",
+["frac78"]="⅞",
+["suphsol"]="⟉",
+["loplus"]="⨭",
+["pointint"]="⨕",
+["cupcap"]="⩆",
+["LessTilde"]="≲",
+["pm"]="±",
+["blacksquare"]="▪",
["plustwo"]="⨧",
-["shchcy"]="щ",
-["cacute"]="ć",
-["Dashv"]="⫤",
-["lHar"]="⥢",
-["NotLeftTriangle"]="⋪",
-["gbreve"]="ğ",
-["boxDl"]="╖",
-["Beta"]="Β",
-["ReverseEquilibrium"]="⇋",
+["copy"]="©",
+["plussim"]="⨦",
+["Lcy"]="Л",
+["pluse"]="⩲",
+["ropar"]="⦆",
+["OpenCurlyQuote"]="‘",
["plusacir"]="⨣",
-["eqslantgtr"]="⪖",
-["ecy"]="э",
-["pitchfork"]="⋔",
-["ctdot"]="⋯",
-["odiv"]="⨸",
-["lesseqqgtr"]="⪋",
-["GreaterLess"]="≷",
-["Ocy"]="О",
-["weierp"]="℘",
-["Uring"]="Ů",
-["period"]=".",
-["nis"]="⋼",
-["cudarrr"]="⤵",
-["boxHU"]="╩",
-["Ouml"]="Ö",
-["Assign"]="≔",
-["Lscr"]="ℒ",
-["parallel"]="∥",
-["there4"]="∴",
-["cupor"]="⩅",
-["nwarr"]="↖",
-["para"]="¶",
-["ouml"]="ö",
-["otimes"]="⊗",
-["drbkarow"]="⤐",
-["puncsp"]=" ",
-["otilde"]="õ",
-["Vvdash"]="⊪",
-["osol"]="⊘",
+["Exists"]="∃",
+["piv"]="ϖ",
+["phmmat"]="ℳ",
+["angzarr"]="⍼",
+["vsupnE"]="⫌︀",
+["phi"]="φ",
+["perp"]="⊥",
+["rdldhar"]="⥩",
+["ccirc"]="ĉ",
+["Tfr"]="𝔗",
+["Tcy"]="Т",
+["circeq"]="≗",
+["InvisibleTimes"]="⁢",
+["OElig"]="Œ",
+["trisb"]="⧍",
+["Rcaron"]="Ř",
+["olt"]="⧀",
+["UpArrow"]="↑",
+["DDotrahd"]="⤑",
+["Uarrocir"]="⥉",
+["lacute"]="ĺ",
["oslash"]="ø",
-["dd"]="ⅆ",
-["NotPrecedesSlantEqual"]="⋠",
-["orv"]="⩛",
-["orslope"]="⩗",
-["KJcy"]="Ќ",
-["larrfs"]="⤝",
-["orderof"]="ℴ",
-["asympeq"]="≍",
-["ord"]="⩝",
-["NotLess"]="≮",
-["NotGreater"]="≯",
-["ThinSpace"]=" ",
-["ominus"]="⊖",
+["Uarr"]="↟",
+["bsolb"]="⧅",
+["gt"]=">",
+["ordm"]="º",
+["Itilde"]="Ĩ",
+["ordm"]="º",
+["Jscr"]="𝒥",
+["Rarr"]="↠",
+["measuredangle"]="∡",
["DoubleLongLeftRightArrow"]="⟺",
-["lesseqgtr"]="⋚",
+["lmidot"]="ŀ",
+["period"]=".",
["operp"]="⦹",
-["quaternions"]="ℍ",
-["boxdR"]="╒",
-["omega"]="ω",
-["Kscr"]="𝒦",
-["lessgtr"]="≶",
-["utilde"]="ũ",
-["olt"]="⧀",
-["Rho"]="Ρ",
-["olcir"]="⦾",
-["oint"]="∮",
+["bprime"]="‵",
+["numsp"]=" ",
+["ominus"]="⊖",
+["nldr"]="‥",
["ograve"]="ò",
-["Succeeds"]="≻",
-["Igrave"]="Ì",
-["eogon"]="ę",
-["Uacute"]="Ú",
-["bbrk"]="⎵",
-["ocy"]="о",
-["bcong"]="≌",
+["omicron"]="ο",
+["nearr"]="↗",
+["jcirc"]="ĵ",
+["nlE"]="≦̸",
+["deg"]="°",
+["frac13"]="⅓",
+["tcy"]="т",
+["lowbar"]="_",
+["vfr"]="𝔳",
+["ogon"]="˛",
+["sim"]="∼",
+["ocirc"]="ô",
+["Icirc"]="Î",
+["ocir"]="⊚",
+["ZeroWidthSpace"]="​",
["oast"]="⊛",
+["smile"]="⌣",
+["bigvee"]="⋁",
["oacute"]="ó",
-["cir"]="○",
-["angmsdab"]="⦩",
-["Iscr"]="ℐ",
-["ldquo"]="“",
-["RightVector"]="⇀",
-["euml"]="ë",
-["between"]="≬",
-["oS"]="Ⓢ",
-["downdownarrows"]="⇊",
-["nvlt"]="<⃒",
-["lurdshar"]="⥊",
-["starf"]="★",
-["xlarr"]="⟵",
-["Aring"]="Å",
-["Xi"]="Ξ",
-["gtcir"]="⩺",
-["Nscr"]="𝒩",
-["elinters"]="⏧",
-["ntrianglelefteq"]="⋬",
-["Vbar"]="⫫",
+["Egrave"]="È",
+["nwnear"]="⤧",
+["nwarhk"]="⤣",
+["rationals"]="ℚ",
+["DiacriticalGrave"]="`",
+["npreceq"]="⪯̸",
+["rarrc"]="⤳",
+["Uogon"]="Ų",
+["InvisibleComma"]="⁣",
+["nvltrie"]="⊴⃒",
+["digamma"]="ϝ",
+["cirE"]="⧃",
+["AMP"]="&",
+["Theta"]="Θ",
+["frac15"]="⅕",
+["fnof"]="ƒ",
+["icirc"]="î",
+["Cdot"]="Ċ",
+["ngsim"]="≵",
+["sube"]="⊆",
+["tcaron"]="ť",
["ntilde"]="ñ",
-["andv"]="⩚",
-["Rsh"]="↱",
-["angmsdad"]="⦫",
-["nsup"]="⊅",
-["nbsp"]=" ",
-["SquareSupersetEqual"]="⊒",
-["ETH"]="Ð",
-["nsube"]="⊈",
-["DoubleContourIntegral"]="∯",
-["nsubE"]="⫅̸",
-["angmsdah"]="⦯",
-["NotLessGreater"]="≸",
-["awint"]="⨑",
-["rtri"]="▹",
-["nsc"]="⊁",
-["boxvl"]="┤",
-["beta"]="β",
-["LessSlantEqual"]="⩽",
-["supsub"]="⫔",
-["agrave"]="à",
-["LeftUpTeeVector"]="⥠",
-["nrarrw"]="↝̸",
-["ltcc"]="⪦",
-["nrarrc"]="⤳̸",
-["frac78"]="⅞",
-["nvrArr"]="⤃",
-["igrave"]="ì",
-["barwed"]="⌅",
-["Mscr"]="ℳ",
-["nrarr"]="↛",
-["SubsetEqual"]="⊆",
-["notnivc"]="⋽",
-["notnivb"]="⋾",
-["succcurlyeq"]="≽",
-["eth"]="ð",
-["notinva"]="∉",
-["Otilde"]="Õ",
-["star"]="☆",
-["rangd"]="⦒",
-["Psi"]="Ψ",
-["nsupe"]="⊉",
-["mapstoup"]="↥",
-["LJcy"]="Љ",
-["looparrowleft"]="↫",
-["nlarr"]="↚",
-["Ll"]="⋘",
-["ordf"]="ª",
-["ni"]="∋",
+["ufr"]="𝔲",
+["Mcy"]="М",
["Delta"]="Δ",
-["NotVerticalBar"]="∤",
-["backcong"]="≌",
-["NoBreak"]="⁠",
+["vnsup"]="⊃⃒",
+["lAtail"]="⤛",
+["DoubleUpArrow"]="⇑",
+["aelig"]="æ",
+["lscr"]="𝓁",
+["Rscr"]="ℛ",
+["capcup"]="⩇",
+["npolint"]="⨔",
+["gesdotol"]="⪄",
+["uacute"]="ú",
+["bumpE"]="⪮",
+["drcorn"]="⌟",
+["notnivb"]="⋾",
+["notinvc"]="⋶",
+["ovbar"]="⌽",
+["Mopf"]="𝕄",
+["NotGreater"]="≯",
+["boxDr"]="╓",
+["lrcorner"]="⌟",
+["nleq"]="≰",
+["nleftarrow"]="↚",
+["nle"]="≰",
+["boxvl"]="┤",
+["Downarrow"]="⇓",
+["hcirc"]="ĥ",
["nharr"]="↮",
+["tfr"]="𝔱",
+["nlt"]="≮",
+["gacute"]="ǵ",
+["colone"]="≔",
+["Rang"]="⟫",
["ngt"]="≯",
-["Pscr"]="𝒫",
-["laemptyv"]="⦴",
-["utrif"]="▴",
-["ngeq"]="≱",
-["ncedil"]="ņ",
-["ncaron"]="ň",
-["boxhu"]="┴",
-["NotSquareSuperset"]="⊐̸",
-["bull"]="•",
+["ntilde"]="ñ",
+["vcy"]="в",
+["boxvL"]="╡",
+["NotLeftTriangleBar"]="⧏̸",
+["NestedGreaterGreater"]="≫",
+["xmap"]="⟼",
+["napid"]="≋̸",
+["LeftTriangleBar"]="⧏",
["SquareSubsetEqual"]="⊑",
-["VerticalSeparator"]="❘",
-["natur"]="♮",
-["ffr"]="𝔣",
-["rdquor"]="”",
-["lagran"]="ℒ",
-["nRightarrow"]="⇏",
-["nLtv"]="≪̸",
-["nLl"]="⋘̸",
-["Epsilon"]="Ε",
-["csup"]="⫐",
-["leftarrow"]="←",
-["nGt"]="≫⃒",
-["multimap"]="⊸",
-["mstpos"]="∾",
-["SuchThat"]="∋",
-["mldr"]="…",
-["midast"]="*",
-["Sum"]="∑",
-["vartheta"]="ϑ",
-["mapsto"]="↦",
-["nsupseteq"]="⊉",
-["Oscr"]="𝒪",
-["forall"]="∀",
-["aring"]="å",
-["ltimes"]="⋉",
-["ltcir"]="⩹",
-["lt"]="<",
-["ii"]="ⅈ",
-["equest"]="≟",
-["scsim"]="≿",
-["lsqb"]="[",
-["lsimg"]="⪏",
-["Egrave"]="È",
-["Downarrow"]="⇓",
-["lsim"]="≲",
-["eqslantless"]="⪕",
-["ucirc"]="û",
-["Auml"]="Ä",
-["lnsim"]="⋦",
-["uplus"]="⊎",
-["lhblk"]="▄",
-["Ugrave"]="Ù",
-["dlcrop"]="⌍",
-["OElig"]="Œ",
-["lesg"]="⋚︀",
-["lesdotor"]="⪃",
-["eg"]="⪚",
-["lvertneqq"]="≨︀",
-["leqslant"]="⩽",
-["ccups"]="⩌",
-["lceil"]="⌈",
-["auml"]="ä",
-["RightCeiling"]="⌉",
-["lbrksld"]="⦏",
-["lbarr"]="⤌",
+["eacute"]="é",
+["ne"]="≠",
+["ncongdot"]="⩭̸",
+["boxvR"]="╞",
+["PrecedesEqual"]="⪯",
+["Omacr"]="Ō",
+["egs"]="⪖",
+["ouml"]="ö",
+["nbsp"]=" ",
+["xuplus"]="⨄",
+["napprox"]="≉",
+["CloseCurlyQuote"]="’",
+["nacute"]="ń",
+["Chi"]="Χ",
+["subsub"]="⫕",
+["gescc"]="⪩",
+["gcirc"]="ĝ",
+["Lsh"]="↰",
+["sfr"]="𝔰",
+["circlearrowright"]="↻",
+["rcaron"]="ř",
+["ThinSpace"]=" ",
+["otilde"]="õ",
+["TRADE"]="™",
+["cudarrl"]="⤸",
["lat"]="⪫",
-["Rscr"]="ℛ",
-["Zcy"]="З",
-["bigwedge"]="⋀",
-["Prime"]="″",
+["nLeftrightarrow"]="⇎",
+["leqq"]="≦",
+["dagger"]="†",
+["dstrok"]="đ",
+["sacute"]="ś",
+["Amacr"]="Ā",
+["mumap"]="⊸",
+["models"]="⊧",
+["DiacriticalAcute"]="´",
+["minusd"]="∸",
+["hybull"]="⁃",
+["ijlig"]="ij",
+["fflig"]="ff",
+["NotGreaterEqual"]="≱",
+["Colon"]="∷",
+["boxV"]="║",
+["DotDot"]="⃜",
+["mdash"]="—",
+["hairsp"]=" ",
+["bcong"]="≌",
+["mcomma"]="⨩",
+["cirfnint"]="⨐",
+["TScy"]="Ц",
+["luruhar"]="⥦",
+["awconint"]="∳",
+["nsim"]="≁",
+["els"]="⪕",
+["imof"]="⊷",
+["lpar"]="(",
+["lozenge"]="◊",
+["oint"]="∮",
+["Umacr"]="Ū",
+["Sum"]="∑",
+["lopar"]="⦅",
+["racute"]="ŕ",
+["LessEqualGreater"]="⋚",
+["Wedge"]="⋀",
+["bbrktbrk"]="⎶",
+["RightDownTeeVector"]="⥝",
+["HumpDownHump"]="≎",
+["rarrb"]="⇥",
+["longleftrightarrow"]="⟷",
+["lnE"]="≨",
+["NotGreaterSlantEqual"]="⩾̸",
+["Nu"]="Ν",
+["NotNestedLessLess"]="⪡̸",
+["UpEquilibrium"]="⥮",
+["boxhD"]="╥",
+["el"]="⪙",
["boxDR"]="╔",
-["scnsim"]="⋩",
-["efDot"]="≒",
-["kopf"]="𝕜",
-["minusdu"]="⨪",
-["kappav"]="ϰ",
+["Gdot"]="Ġ",
+["itilde"]="ĩ",
+["isindot"]="⋵",
+["GreaterEqualLess"]="⋛",
+["Ll"]="⋘",
+["nrarrw"]="↝̸",
+["supnE"]="⫌",
+["epsiv"]="ϵ",
+["Element"]="∈",
+["gtreqless"]="⋛",
+["laemptyv"]="⦴",
+["nGt"]="≫⃒",
+["angsph"]="∢",
+["lE"]="≦",
+["kscr"]="𝓀",
+["Ocy"]="О",
+["LowerLeftArrow"]="↙",
+["dopf"]="𝕕",
+["iukcy"]="і",
+["atilde"]="ã",
+["DoubleRightArrow"]="⇒",
+["oslash"]="ø",
+["rarr"]="→",
+["intprod"]="⨼",
+["hookrightarrow"]="↪",
+["intcal"]="⊺",
+["infintie"]="⧝",
+["escr"]="ℯ",
+["iiota"]="℩",
+["curren"]="¤",
+["Bernoullis"]="ℬ",
+["angmsdah"]="⦯",
+["ShortRightArrow"]="→",
+["boxUR"]="╚",
+["ges"]="⩾",
+["DoubleDownArrow"]="⇓",
+["NotSquareSuperset"]="⊐̸",
+["lsim"]="≲",
+["bump"]="≎",
+["curlyeqsucc"]="⋟",
+["SHCHcy"]="Щ",
+["frac45"]="⅘",
+["qint"]="⨌",
+["Precedes"]="≺",
+["RightTeeArrow"]="↦",
+["frac16"]="⅙",
+["euro"]="€",
+["smtes"]="⪬︀",
+["eth"]="ð",
+["ldquo"]="“",
+["equivDD"]="⩸",
+["Oopf"]="𝕆",
["boxVh"]="╫",
-["Uuml"]="Ü",
-["centerdot"]="·",
-["isinsv"]="⋳",
-["isins"]="⋴",
-["bot"]="⊥",
-["integers"]="ℤ",
-["Racute"]="Ŕ",
-["ijlig"]="ij",
-["bernou"]="ℬ",
-["Cconint"]="∰",
-["doteq"]="≐",
-["hookleftarrow"]="↩",
-["epar"]="⋕",
-["harrw"]="↭",
-["dzigrarr"]="⟿",
-["Zscr"]="𝒵",
-["alpha"]="α",
-["times"]="×",
+["GreaterSlantEqual"]="⩾",
+["KJcy"]="Ќ",
["egrave"]="è",
-["UnionPlus"]="⊎",
-["Qscr"]="𝒬",
-["Omacr"]="Ō",
-["Zfr"]="ℨ",
-["gneq"]="⪈",
-["divonx"]="⋇",
-["gesdotol"]="⪄",
-["gvertneqq"]="≩︀",
-["geq"]="≥",
-["utri"]="▵",
-["ge"]="≥",
-["vArr"]="⇕",
-["Rrightarrow"]="⇛",
-["frac25"]="⅖",
-["LeftCeiling"]="⌈",
-["GreaterGreater"]="⪢",
-["LT"]="<",
-["Longrightarrow"]="⟹",
-["eqcolon"]="≕",
-["ofcir"]="⦿",
-["boxUl"]="╜",
-["Wscr"]="𝒲",
-["Sacute"]="Ś",
-["Union"]="⋃",
-["gg"]="≫",
-["DownArrowBar"]="⤓",
-["Escr"]="ℰ",
-["ecirc"]="ê",
-["Lmidot"]="Ŀ",
-["Wedge"]="⋀",
-["frown"]="⌢",
-["ring"]="˚",
-["dtdot"]="⋱",
-["Ccedil"]="Ç",
-["Conint"]="∯",
-["dscr"]="𝒹",
-["Map"]="⤅",
-["EmptyVerySmallSquare"]="▫",
-["backsim"]="∽",
-["angzarr"]="⍼",
-["dHar"]="⥥",
-["Mfr"]="𝔐",
-["cirE"]="⧃",
-["Popf"]="ℙ",
-["NestedGreaterGreater"]="≫",
-["ReverseElement"]="∋",
-["boxVr"]="╟",
+["NotGreaterLess"]="≹",
+["boxVl"]="╢",
+["MediumSpace"]=" ",
+["LongLeftArrow"]="⟵",
+["uarr"]="↑",
+["Ocirc"]="Ô",
+["Idot"]="İ",
+["bumpe"]="≏",
+["nwArr"]="⇖",
+["NegativeThinSpace"]="​",
+["coprod"]="∐",
+["VerticalBar"]="∣",
+["sccue"]="≽",
+["boxDl"]="╖",
+["NotSubset"]="⊂⃒",
+["Edot"]="Ė",
+["scy"]="с",
+["Cup"]="⋓",
+["centerdot"]="·",
+["nsimeq"]="≄",
+["DownLeftRightVector"]="⥐",
}
diff --git a/Master/texmf-dist/tex/luatex/luaxml/luaxml-transform.lua b/Master/texmf-dist/tex/luatex/luaxml/luaxml-transform.lua
index b6841fea5fb..4b51eed1170 100644
--- a/Master/texmf-dist/tex/luatex/luaxml/luaxml-transform.lua
+++ b/Master/texmf-dist/tex/luatex/luaxml/luaxml-transform.lua
@@ -198,6 +198,10 @@ local function add_action(selector, template, parameters, csspar)
end
+local function reset_actions(selector, csspar)
+ local css = csspar or css
+ css:remove_selector(selector)
+end
--- Transform XML string
@@ -243,7 +247,7 @@ end
local Transformer
--- Make new Transformer object
--- @return Tranformer object
+-- @return Transformer object
local function new()
local self = setmetatable({}, Transformer)
self.css = cssquery()
@@ -289,6 +293,12 @@ function Transformer:add_custom_action(selector, fn )
add_custom_action(selector, fn, self.css)
end
+--- Remove all actions that match the given selector
+---@param selector string
+function Transformer:reset_actions(selector)
+ reset_actions(selector, self.css)
+end
+
-- all methods that use transformation functions must
-- correctly handle the cssquery object that this library uses
@@ -338,6 +348,7 @@ local M = {
print_tex = print_tex,
add_action = add_action,
add_custom_action = add_custom_action,
+ reset_actions = reset_actions,
simple_content = simple_content,
load_file = load_file,
process_dom = process_dom,
diff --git a/Master/texmf-dist/tex/luatex/markdown/markdown-parser.lua b/Master/texmf-dist/tex/luatex/markdown/markdown-parser.lua
new file mode 100644
index 00000000000..2cdcf3ff759
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/markdown/markdown-parser.lua
@@ -0,0 +1,8990 @@
+--
+-- Copyright (C) 2009-2016 John MacFarlane, Hans Hagen
+--
+-- Permission is hereby granted, free of charge, to any person obtaining
+-- a copy of this software and associated documentation files (the
+-- "Software"), to deal in the Software without restriction, including
+-- without limitation the rights to use, copy, modify, merge, publish,
+-- distribute, sublicense, and/or sell copies of the Software, and to
+-- permit persons to whom the Software is furnished to do so, subject to
+-- the following conditions:
+--
+-- The above copyright notice and this permission notice shall be
+-- included in all copies or substantial portions of the Software.
+--
+-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+-- MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND NONINFRINGEMENT.
+-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+--
+-- Copyright (C) 2016-2024 Vít Starý Novotný, Andrej Genčur
+--
+-- This work may be distributed and/or modified under the
+-- conditions of the LaTeX Project Public License, either version 1.3
+-- of this license or (at your option) any later version.
+-- The latest version of this license is in
+--
+-- http://www.latex-project.org/lppl.txt
+--
+-- and version 1.3 or later is part of all distributions of LaTeX
+-- version 2005/12/01 or later.
+--
+-- This work has the LPPL maintenance status `maintained'.
+-- The Current Maintainer of this work is Vít Starý Novotný.
+--
+-- Send bug reports, requests for additions and questions
+-- either to the GitHub issue tracker at
+--
+-- https://github.com/witiko/markdown/issues
+--
+-- or to the e-mail address <witiko@mail.muni.cz>.
+--
+-- MODIFICATION ADVICE:
+--
+-- If you want to customize this file, it is best to make a copy of
+-- the source file(s) from which it was produced. Use a different
+-- name for your copy(ies) and modify the copy(ies); this will ensure
+-- that your modifications do not get overwritten when you install a
+-- new release of the standard system. You should also ensure that
+-- your modified source file does not generate any modified file with
+-- the same name as a standard file.
+--
+-- You will also need to produce your own, suitably named, .ins file to
+-- control the generation of files from your source file; this file
+-- should contain your own preambles for the files it generates, not
+-- those in the standard .ins files.
+--
+local metadata = {
+ version = "3.7.0-0-g98dece19",
+ comment = "A module for the conversion from markdown "
+ .. "to plain TeX",
+ author = "John MacFarlane, Hans Hagen, Vít Starý Novotný, "
+ .. "Andrej Genčur",
+ copyright = {"2009-2016 John MacFarlane, Hans Hagen",
+ "2016-2024 Vít Starý Novotný, Andrej Genčur"},
+ license = "LPPL 1.3c"
+}
+
+if not modules then modules = { } end
+modules['markdown'] = metadata
+local lpeg = require("lpeg")
+local unicode = require("unicode")
+local md5 = require("md5");
+(function()
+ local should_initialize = package.loaded.kpse == nil
+ or tex.initialize ~= nil
+ kpse = require("kpse")
+ if should_initialize then
+ kpse.set_program_name("luatex")
+ end
+end)()
+local uni_algos = require("lua-uni-algos")
+local M = {metadata = metadata}
+local walkable_syntax = {
+ Block = {
+ "Blockquote",
+ "Verbatim",
+ "ThematicBreak",
+ "BulletList",
+ "OrderedList",
+ "DisplayHtml",
+ "Heading",
+ },
+ BlockOrParagraph = {
+ "Block",
+ "Paragraph",
+ "Plain",
+ },
+ Inline = {
+ "Str",
+ "Space",
+ "Endline",
+ "EndlineBreak",
+ "LinkAndEmph",
+ "Code",
+ "AutoLinkUrl",
+ "AutoLinkEmail",
+ "AutoLinkRelativeReference",
+ "InlineHtml",
+ "HtmlEntity",
+ "EscapedChar",
+ "Smart",
+ "Symbol",
+ },
+}
+local defaultOptions = {}
+defaultOptions.eagerCache = true
+defaultOptions.singletonCache = true
+local singletonCache = {
+ convert = nil,
+ options = nil,
+}
+defaultOptions.unicodeNormalization = true
+defaultOptions.unicodeNormalizationForm = "nfc"
+defaultOptions.cacheDir = "."
+defaultOptions.contentBlocksLanguageMap = "markdown-languages.json"
+defaultOptions.debugExtensionsFileName = "debug-extensions.json"
+defaultOptions.frozenCacheFileName = "frozenCache.tex"
+defaultOptions.autoIdentifiers = false
+defaultOptions.blankBeforeBlockquote = false
+defaultOptions.blankBeforeCodeFence = false
+defaultOptions.blankBeforeDivFence = false
+defaultOptions.blankBeforeHeading = false
+defaultOptions.blankBeforeList = false
+defaultOptions.bracketedSpans = false
+defaultOptions.breakableBlockquotes = true
+defaultOptions.citationNbsps = true
+defaultOptions.citations = false
+defaultOptions.codeSpans = true
+defaultOptions.contentBlocks = false
+defaultOptions.contentLevel = "block"
+defaultOptions.debugExtensions = false
+defaultOptions.definitionLists = false
+defaultOptions.ensureJekyllData = false
+defaultOptions.expectJekyllData = false
+metadata.user_extension_api_version = 2
+metadata.grammar_version = 4
+defaultOptions.extensions = {}
+defaultOptions.fancyLists = false
+defaultOptions.fencedCode = true
+defaultOptions.fencedCodeAttributes = false
+defaultOptions.fencedDivs = false
+defaultOptions.finalizeCache = false
+defaultOptions.frozenCacheCounter = 0
+defaultOptions.gfmAutoIdentifiers = false
+defaultOptions.hashEnumerators = false
+defaultOptions.headerAttributes = false
+defaultOptions.html = true
+defaultOptions.hybrid = false
+defaultOptions.inlineCodeAttributes = false
+defaultOptions.inlineNotes = false
+defaultOptions.jekyllData = false
+defaultOptions.linkAttributes = false
+defaultOptions.lineBlocks = false
+defaultOptions.mark = false
+defaultOptions.notes = false
+defaultOptions.pipeTables = false
+defaultOptions.preserveTabs = true
+defaultOptions.rawAttribute = false
+defaultOptions.relativeReferences = false
+defaultOptions.shiftHeadings = 0
+defaultOptions.slice = "^ $"
+defaultOptions.smartEllipses = false
+defaultOptions.startNumber = true
+defaultOptions.strikeThrough = false
+defaultOptions.stripIndent = false
+defaultOptions.subscripts = false
+defaultOptions.superscripts = false
+defaultOptions.tableAttributes = false
+defaultOptions.tableCaptions = false
+defaultOptions.taskLists = false
+defaultOptions.texComments = false
+defaultOptions.texMathDollars = false
+defaultOptions.texMathDoubleBackslash = false
+defaultOptions.texMathSingleBackslash = false
+defaultOptions.tightLists = true
+defaultOptions.underscores = true
+local upper, format, length =
+ string.upper, string.format, string.len
+local P, R, S, V, C, Cg, Cb, Cmt, Cc, Ct, B, Cs, Cp, any =
+ lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.C, lpeg.Cg, lpeg.Cb,
+ lpeg.Cmt, lpeg.Cc, lpeg.Ct, lpeg.B, lpeg.Cs, lpeg.Cp, lpeg.P(1)
+local util = {}
+function util.err(msg, exit_code)
+ io.stderr:write("markdown.lua: " .. msg .. "\n")
+ os.exit(exit_code or 1)
+end
+function util.cache(dir, string, salt, transform, suffix)
+ local digest = md5.sumhexa(string .. (salt or ""))
+ local name = util.pathname(dir, digest .. suffix)
+ local file = io.open(name, "r")
+ if file == nil then -- If no cache entry exists, create a new one.
+ file = assert(io.open(name, "w"),
+ [[Could not open file "]] .. name .. [[" for writing]])
+ local result = string
+ if transform ~= nil then
+ result = transform(result)
+ end
+ assert(file:write(result))
+ assert(file:close())
+ end
+ return name
+end
+function util.cache_verbatim(dir, string)
+ local name = util.cache(dir, string, nil, nil, ".verbatim")
+ return name
+end
+function util.table_copy(t)
+ local u = { }
+ for k, v in pairs(t) do u[k] = v end
+ return setmetatable(u, getmetatable(t))
+end
+function util.encode_json_string(s)
+ s = s:gsub([[\]], [[\\]])
+ s = s:gsub([["]], [[\"]])
+ return [["]] .. s .. [["]]
+end
+function util.expand_tabs_in_line(s, tabstop)
+ local tab = tabstop or 4
+ local corr = 0
+ return (s:gsub("()\t", function(p)
+ local sp = tab - (p - 1 + corr) % tab
+ corr = corr - 1 + sp
+ return string.rep(" ", sp)
+ end))
+end
+function util.walk(t, f)
+ local typ = type(t)
+ if typ == "string" then
+ f(t)
+ elseif typ == "table" then
+ local i = 1
+ local n
+ n = t[i]
+ while n do
+ util.walk(n, f)
+ i = i + 1
+ n = t[i]
+ end
+ elseif typ == "function" then
+ local ok, val = pcall(t)
+ if ok then
+ util.walk(val,f)
+ end
+ else
+ f(tostring(t))
+ end
+end
+function util.flatten(ary)
+ local new = {}
+ for _,v in ipairs(ary) do
+ if type(v) == "table" then
+ for _,w in ipairs(util.flatten(v)) do
+ new[#new + 1] = w
+ end
+ else
+ new[#new + 1] = v
+ end
+ end
+ return new
+end
+function util.rope_to_string(rope)
+ local buffer = {}
+ util.walk(rope, function(x) buffer[#buffer + 1] = x end)
+ return table.concat(buffer)
+end
+function util.rope_last(rope)
+ if #rope == 0 then
+ return nil
+ else
+ local l = rope[#rope]
+ if type(l) == "table" then
+ return util.rope_last(l)
+ else
+ return l
+ end
+ end
+end
+function util.intersperse(ary, x)
+ local new = {}
+ local l = #ary
+ for i,v in ipairs(ary) do
+ local n = #new
+ new[n + 1] = v
+ if i ~= l then
+ new[n + 2] = x
+ end
+ end
+ return new
+end
+function util.map(ary, f)
+ local new = {}
+ for i,v in ipairs(ary) do
+ new[i] = f(v)
+ end
+ return new
+end
+function util.escaper(char_escapes, string_escapes)
+ local char_escapes_list = ""
+ for i,_ in pairs(char_escapes) do
+ char_escapes_list = char_escapes_list .. i
+ end
+ local escapable = S(char_escapes_list) / char_escapes
+ if string_escapes then
+ for k,v in pairs(string_escapes) do
+ escapable = P(k) / v + escapable
+ end
+ end
+ local escape_string = Cs((escapable + any)^0)
+ return function(s)
+ return lpeg.match(escape_string, s)
+ end
+end
+function util.pathname(dir, file)
+ if #dir == 0 then
+ return file
+ else
+ return dir .. "/" .. file
+ end
+end
+function util.salt(options)
+ local opt_string = {}
+ for k, _ in pairs(defaultOptions) do
+ local v = options[k]
+ if type(v) == "table" then
+ for _, i in ipairs(v) do
+ opt_string[#opt_string+1] = k .. "=" .. tostring(i)
+ end
+ elseif k ~= "cacheDir" then
+ opt_string[#opt_string+1] = k .. "=" .. tostring(v)
+ end
+ end
+ table.sort(opt_string)
+ local salt = table.concat(opt_string, ",")
+ .. "," .. metadata.version
+ return salt
+end
+local entities = {}
+
+local character_entities = {
+ ["Tab"] = 9,
+ ["NewLine"] = 10,
+ ["excl"] = 33,
+ ["QUOT"] = 34,
+ ["quot"] = 34,
+ ["num"] = 35,
+ ["dollar"] = 36,
+ ["percnt"] = 37,
+ ["AMP"] = 38,
+ ["amp"] = 38,
+ ["apos"] = 39,
+ ["lpar"] = 40,
+ ["rpar"] = 41,
+ ["ast"] = 42,
+ ["midast"] = 42,
+ ["plus"] = 43,
+ ["comma"] = 44,
+ ["period"] = 46,
+ ["sol"] = 47,
+ ["colon"] = 58,
+ ["semi"] = 59,
+ ["LT"] = 60,
+ ["lt"] = 60,
+ ["nvlt"] = {60, 8402},
+ ["bne"] = {61, 8421},
+ ["equals"] = 61,
+ ["GT"] = 62,
+ ["gt"] = 62,
+ ["nvgt"] = {62, 8402},
+ ["quest"] = 63,
+ ["commat"] = 64,
+ ["lbrack"] = 91,
+ ["lsqb"] = 91,
+ ["bsol"] = 92,
+ ["rbrack"] = 93,
+ ["rsqb"] = 93,
+ ["Hat"] = 94,
+ ["UnderBar"] = 95,
+ ["lowbar"] = 95,
+ ["DiacriticalGrave"] = 96,
+ ["grave"] = 96,
+ ["fjlig"] = {102, 106},
+ ["lbrace"] = 123,
+ ["lcub"] = 123,
+ ["VerticalLine"] = 124,
+ ["verbar"] = 124,
+ ["vert"] = 124,
+ ["rbrace"] = 125,
+ ["rcub"] = 125,
+ ["NonBreakingSpace"] = 160,
+ ["nbsp"] = 160,
+ ["iexcl"] = 161,
+ ["cent"] = 162,
+ ["pound"] = 163,
+ ["curren"] = 164,
+ ["yen"] = 165,
+ ["brvbar"] = 166,
+ ["sect"] = 167,
+ ["Dot"] = 168,
+ ["DoubleDot"] = 168,
+ ["die"] = 168,
+ ["uml"] = 168,
+ ["COPY"] = 169,
+ ["copy"] = 169,
+ ["ordf"] = 170,
+ ["laquo"] = 171,
+ ["not"] = 172,
+ ["shy"] = 173,
+ ["REG"] = 174,
+ ["circledR"] = 174,
+ ["reg"] = 174,
+ ["macr"] = 175,
+ ["strns"] = 175,
+ ["deg"] = 176,
+ ["PlusMinus"] = 177,
+ ["plusmn"] = 177,
+ ["pm"] = 177,
+ ["sup2"] = 178,
+ ["sup3"] = 179,
+ ["DiacriticalAcute"] = 180,
+ ["acute"] = 180,
+ ["micro"] = 181,
+ ["para"] = 182,
+ ["CenterDot"] = 183,
+ ["centerdot"] = 183,
+ ["middot"] = 183,
+ ["Cedilla"] = 184,
+ ["cedil"] = 184,
+ ["sup1"] = 185,
+ ["ordm"] = 186,
+ ["raquo"] = 187,
+ ["frac14"] = 188,
+ ["frac12"] = 189,
+ ["half"] = 189,
+ ["frac34"] = 190,
+ ["iquest"] = 191,
+ ["Agrave"] = 192,
+ ["Aacute"] = 193,
+ ["Acirc"] = 194,
+ ["Atilde"] = 195,
+ ["Auml"] = 196,
+ ["Aring"] = 197,
+ ["angst"] = 197,
+ ["AElig"] = 198,
+ ["Ccedil"] = 199,
+ ["Egrave"] = 200,
+ ["Eacute"] = 201,
+ ["Ecirc"] = 202,
+ ["Euml"] = 203,
+ ["Igrave"] = 204,
+ ["Iacute"] = 205,
+ ["Icirc"] = 206,
+ ["Iuml"] = 207,
+ ["ETH"] = 208,
+ ["Ntilde"] = 209,
+ ["Ograve"] = 210,
+ ["Oacute"] = 211,
+ ["Ocirc"] = 212,
+ ["Otilde"] = 213,
+ ["Ouml"] = 214,
+ ["times"] = 215,
+ ["Oslash"] = 216,
+ ["Ugrave"] = 217,
+ ["Uacute"] = 218,
+ ["Ucirc"] = 219,
+ ["Uuml"] = 220,
+ ["Yacute"] = 221,
+ ["THORN"] = 222,
+ ["szlig"] = 223,
+ ["agrave"] = 224,
+ ["aacute"] = 225,
+ ["acirc"] = 226,
+ ["atilde"] = 227,
+ ["auml"] = 228,
+ ["aring"] = 229,
+ ["aelig"] = 230,
+ ["ccedil"] = 231,
+ ["egrave"] = 232,
+ ["eacute"] = 233,
+ ["ecirc"] = 234,
+ ["euml"] = 235,
+ ["igrave"] = 236,
+ ["iacute"] = 237,
+ ["icirc"] = 238,
+ ["iuml"] = 239,
+ ["eth"] = 240,
+ ["ntilde"] = 241,
+ ["ograve"] = 242,
+ ["oacute"] = 243,
+ ["ocirc"] = 244,
+ ["otilde"] = 245,
+ ["ouml"] = 246,
+ ["div"] = 247,
+ ["divide"] = 247,
+ ["oslash"] = 248,
+ ["ugrave"] = 249,
+ ["uacute"] = 250,
+ ["ucirc"] = 251,
+ ["uuml"] = 252,
+ ["yacute"] = 253,
+ ["thorn"] = 254,
+ ["yuml"] = 255,
+ ["Amacr"] = 256,
+ ["amacr"] = 257,
+ ["Abreve"] = 258,
+ ["abreve"] = 259,
+ ["Aogon"] = 260,
+ ["aogon"] = 261,
+ ["Cacute"] = 262,
+ ["cacute"] = 263,
+ ["Ccirc"] = 264,
+ ["ccirc"] = 265,
+ ["Cdot"] = 266,
+ ["cdot"] = 267,
+ ["Ccaron"] = 268,
+ ["ccaron"] = 269,
+ ["Dcaron"] = 270,
+ ["dcaron"] = 271,
+ ["Dstrok"] = 272,
+ ["dstrok"] = 273,
+ ["Emacr"] = 274,
+ ["emacr"] = 275,
+ ["Edot"] = 278,
+ ["edot"] = 279,
+ ["Eogon"] = 280,
+ ["eogon"] = 281,
+ ["Ecaron"] = 282,
+ ["ecaron"] = 283,
+ ["Gcirc"] = 284,
+ ["gcirc"] = 285,
+ ["Gbreve"] = 286,
+ ["gbreve"] = 287,
+ ["Gdot"] = 288,
+ ["gdot"] = 289,
+ ["Gcedil"] = 290,
+ ["Hcirc"] = 292,
+ ["hcirc"] = 293,
+ ["Hstrok"] = 294,
+ ["hstrok"] = 295,
+ ["Itilde"] = 296,
+ ["itilde"] = 297,
+ ["Imacr"] = 298,
+ ["imacr"] = 299,
+ ["Iogon"] = 302,
+ ["iogon"] = 303,
+ ["Idot"] = 304,
+ ["imath"] = 305,
+ ["inodot"] = 305,
+ ["IJlig"] = 306,
+ ["ijlig"] = 307,
+ ["Jcirc"] = 308,
+ ["jcirc"] = 309,
+ ["Kcedil"] = 310,
+ ["kcedil"] = 311,
+ ["kgreen"] = 312,
+ ["Lacute"] = 313,
+ ["lacute"] = 314,
+ ["Lcedil"] = 315,
+ ["lcedil"] = 316,
+ ["Lcaron"] = 317,
+ ["lcaron"] = 318,
+ ["Lmidot"] = 319,
+ ["lmidot"] = 320,
+ ["Lstrok"] = 321,
+ ["lstrok"] = 322,
+ ["Nacute"] = 323,
+ ["nacute"] = 324,
+ ["Ncedil"] = 325,
+ ["ncedil"] = 326,
+ ["Ncaron"] = 327,
+ ["ncaron"] = 328,
+ ["napos"] = 329,
+ ["ENG"] = 330,
+ ["eng"] = 331,
+ ["Omacr"] = 332,
+ ["omacr"] = 333,
+ ["Odblac"] = 336,
+ ["odblac"] = 337,
+ ["OElig"] = 338,
+ ["oelig"] = 339,
+ ["Racute"] = 340,
+ ["racute"] = 341,
+ ["Rcedil"] = 342,
+ ["rcedil"] = 343,
+ ["Rcaron"] = 344,
+ ["rcaron"] = 345,
+ ["Sacute"] = 346,
+ ["sacute"] = 347,
+ ["Scirc"] = 348,
+ ["scirc"] = 349,
+ ["Scedil"] = 350,
+ ["scedil"] = 351,
+ ["Scaron"] = 352,
+ ["scaron"] = 353,
+ ["Tcedil"] = 354,
+ ["tcedil"] = 355,
+ ["Tcaron"] = 356,
+ ["tcaron"] = 357,
+ ["Tstrok"] = 358,
+ ["tstrok"] = 359,
+ ["Utilde"] = 360,
+ ["utilde"] = 361,
+ ["Umacr"] = 362,
+ ["umacr"] = 363,
+ ["Ubreve"] = 364,
+ ["ubreve"] = 365,
+ ["Uring"] = 366,
+ ["uring"] = 367,
+ ["Udblac"] = 368,
+ ["udblac"] = 369,
+ ["Uogon"] = 370,
+ ["uogon"] = 371,
+ ["Wcirc"] = 372,
+ ["wcirc"] = 373,
+ ["Ycirc"] = 374,
+ ["ycirc"] = 375,
+ ["Yuml"] = 376,
+ ["Zacute"] = 377,
+ ["zacute"] = 378,
+ ["Zdot"] = 379,
+ ["zdot"] = 380,
+ ["Zcaron"] = 381,
+ ["zcaron"] = 382,
+ ["fnof"] = 402,
+ ["imped"] = 437,
+ ["gacute"] = 501,
+ ["jmath"] = 567,
+ ["circ"] = 710,
+ ["Hacek"] = 711,
+ ["caron"] = 711,
+ ["Breve"] = 728,
+ ["breve"] = 728,
+ ["DiacriticalDot"] = 729,
+ ["dot"] = 729,
+ ["ring"] = 730,
+ ["ogon"] = 731,
+ ["DiacriticalTilde"] = 732,
+ ["tilde"] = 732,
+ ["DiacriticalDoubleAcute"] = 733,
+ ["dblac"] = 733,
+ ["DownBreve"] = 785,
+ ["Alpha"] = 913,
+ ["Beta"] = 914,
+ ["Gamma"] = 915,
+ ["Delta"] = 916,
+ ["Epsilon"] = 917,
+ ["Zeta"] = 918,
+ ["Eta"] = 919,
+ ["Theta"] = 920,
+ ["Iota"] = 921,
+ ["Kappa"] = 922,
+ ["Lambda"] = 923,
+ ["Mu"] = 924,
+ ["Nu"] = 925,
+ ["Xi"] = 926,
+ ["Omicron"] = 927,
+ ["Pi"] = 928,
+ ["Rho"] = 929,
+ ["Sigma"] = 931,
+ ["Tau"] = 932,
+ ["Upsilon"] = 933,
+ ["Phi"] = 934,
+ ["Chi"] = 935,
+ ["Psi"] = 936,
+ ["Omega"] = 937,
+ ["ohm"] = 937,
+ ["alpha"] = 945,
+ ["beta"] = 946,
+ ["gamma"] = 947,
+ ["delta"] = 948,
+ ["epsi"] = 949,
+ ["epsilon"] = 949,
+ ["zeta"] = 950,
+ ["eta"] = 951,
+ ["theta"] = 952,
+ ["iota"] = 953,
+ ["kappa"] = 954,
+ ["lambda"] = 955,
+ ["mu"] = 956,
+ ["nu"] = 957,
+ ["xi"] = 958,
+ ["omicron"] = 959,
+ ["pi"] = 960,
+ ["rho"] = 961,
+ ["sigmaf"] = 962,
+ ["sigmav"] = 962,
+ ["varsigma"] = 962,
+ ["sigma"] = 963,
+ ["tau"] = 964,
+ ["upsi"] = 965,
+ ["upsilon"] = 965,
+ ["phi"] = 966,
+ ["chi"] = 967,
+ ["psi"] = 968,
+ ["omega"] = 969,
+ ["thetasym"] = 977,
+ ["thetav"] = 977,
+ ["vartheta"] = 977,
+ ["Upsi"] = 978,
+ ["upsih"] = 978,
+ ["phiv"] = 981,
+ ["straightphi"] = 981,
+ ["varphi"] = 981,
+ ["piv"] = 982,
+ ["varpi"] = 982,
+ ["Gammad"] = 988,
+ ["digamma"] = 989,
+ ["gammad"] = 989,
+ ["kappav"] = 1008,
+ ["varkappa"] = 1008,
+ ["rhov"] = 1009,
+ ["varrho"] = 1009,
+ ["epsiv"] = 1013,
+ ["straightepsilon"] = 1013,
+ ["varepsilon"] = 1013,
+ ["backepsilon"] = 1014,
+ ["bepsi"] = 1014,
+ ["IOcy"] = 1025,
+ ["DJcy"] = 1026,
+ ["GJcy"] = 1027,
+ ["Jukcy"] = 1028,
+ ["DScy"] = 1029,
+ ["Iukcy"] = 1030,
+ ["YIcy"] = 1031,
+ ["Jsercy"] = 1032,
+ ["LJcy"] = 1033,
+ ["NJcy"] = 1034,
+ ["TSHcy"] = 1035,
+ ["KJcy"] = 1036,
+ ["Ubrcy"] = 1038,
+ ["DZcy"] = 1039,
+ ["Acy"] = 1040,
+ ["Bcy"] = 1041,
+ ["Vcy"] = 1042,
+ ["Gcy"] = 1043,
+ ["Dcy"] = 1044,
+ ["IEcy"] = 1045,
+ ["ZHcy"] = 1046,
+ ["Zcy"] = 1047,
+ ["Icy"] = 1048,
+ ["Jcy"] = 1049,
+ ["Kcy"] = 1050,
+ ["Lcy"] = 1051,
+ ["Mcy"] = 1052,
+ ["Ncy"] = 1053,
+ ["Ocy"] = 1054,
+ ["Pcy"] = 1055,
+ ["Rcy"] = 1056,
+ ["Scy"] = 1057,
+ ["Tcy"] = 1058,
+ ["Ucy"] = 1059,
+ ["Fcy"] = 1060,
+ ["KHcy"] = 1061,
+ ["TScy"] = 1062,
+ ["CHcy"] = 1063,
+ ["SHcy"] = 1064,
+ ["SHCHcy"] = 1065,
+ ["HARDcy"] = 1066,
+ ["Ycy"] = 1067,
+ ["SOFTcy"] = 1068,
+ ["Ecy"] = 1069,
+ ["YUcy"] = 1070,
+ ["YAcy"] = 1071,
+ ["acy"] = 1072,
+ ["bcy"] = 1073,
+ ["vcy"] = 1074,
+ ["gcy"] = 1075,
+ ["dcy"] = 1076,
+ ["iecy"] = 1077,
+ ["zhcy"] = 1078,
+ ["zcy"] = 1079,
+ ["icy"] = 1080,
+ ["jcy"] = 1081,
+ ["kcy"] = 1082,
+ ["lcy"] = 1083,
+ ["mcy"] = 1084,
+ ["ncy"] = 1085,
+ ["ocy"] = 1086,
+ ["pcy"] = 1087,
+ ["rcy"] = 1088,
+ ["scy"] = 1089,
+ ["tcy"] = 1090,
+ ["ucy"] = 1091,
+ ["fcy"] = 1092,
+ ["khcy"] = 1093,
+ ["tscy"] = 1094,
+ ["chcy"] = 1095,
+ ["shcy"] = 1096,
+ ["shchcy"] = 1097,
+ ["hardcy"] = 1098,
+ ["ycy"] = 1099,
+ ["softcy"] = 1100,
+ ["ecy"] = 1101,
+ ["yucy"] = 1102,
+ ["yacy"] = 1103,
+ ["iocy"] = 1105,
+ ["djcy"] = 1106,
+ ["gjcy"] = 1107,
+ ["jukcy"] = 1108,
+ ["dscy"] = 1109,
+ ["iukcy"] = 1110,
+ ["yicy"] = 1111,
+ ["jsercy"] = 1112,
+ ["ljcy"] = 1113,
+ ["njcy"] = 1114,
+ ["tshcy"] = 1115,
+ ["kjcy"] = 1116,
+ ["ubrcy"] = 1118,
+ ["dzcy"] = 1119,
+ ["ensp"] = 8194,
+ ["emsp"] = 8195,
+ ["emsp13"] = 8196,
+ ["emsp14"] = 8197,
+ ["numsp"] = 8199,
+ ["puncsp"] = 8200,
+ ["ThinSpace"] = 8201,
+ ["thinsp"] = 8201,
+ ["VeryThinSpace"] = 8202,
+ ["hairsp"] = 8202,
+ ["NegativeMediumSpace"] = 8203,
+ ["NegativeThickSpace"] = 8203,
+ ["NegativeThinSpace"] = 8203,
+ ["NegativeVeryThinSpace"] = 8203,
+ ["ZeroWidthSpace"] = 8203,
+ ["zwnj"] = 8204,
+ ["zwj"] = 8205,
+ ["lrm"] = 8206,
+ ["rlm"] = 8207,
+ ["dash"] = 8208,
+ ["hyphen"] = 8208,
+ ["ndash"] = 8211,
+ ["mdash"] = 8212,
+ ["horbar"] = 8213,
+ ["Verbar"] = 8214,
+ ["Vert"] = 8214,
+ ["OpenCurlyQuote"] = 8216,
+ ["lsquo"] = 8216,
+ ["CloseCurlyQuote"] = 8217,
+ ["rsquo"] = 8217,
+ ["rsquor"] = 8217,
+ ["lsquor"] = 8218,
+ ["sbquo"] = 8218,
+ ["OpenCurlyDoubleQuote"] = 8220,
+ ["ldquo"] = 8220,
+ ["CloseCurlyDoubleQuote"] = 8221,
+ ["rdquo"] = 8221,
+ ["rdquor"] = 8221,
+ ["bdquo"] = 8222,
+ ["ldquor"] = 8222,
+ ["dagger"] = 8224,
+ ["Dagger"] = 8225,
+ ["ddagger"] = 8225,
+ ["bull"] = 8226,
+ ["bullet"] = 8226,
+ ["nldr"] = 8229,
+ ["hellip"] = 8230,
+ ["mldr"] = 8230,
+ ["permil"] = 8240,
+ ["pertenk"] = 8241,
+ ["prime"] = 8242,
+ ["Prime"] = 8243,
+ ["tprime"] = 8244,
+ ["backprime"] = 8245,
+ ["bprime"] = 8245,
+ ["lsaquo"] = 8249,
+ ["rsaquo"] = 8250,
+ ["OverBar"] = 8254,
+ ["oline"] = 8254,
+ ["caret"] = 8257,
+ ["hybull"] = 8259,
+ ["frasl"] = 8260,
+ ["bsemi"] = 8271,
+ ["qprime"] = 8279,
+ ["MediumSpace"] = 8287,
+ ["ThickSpace"] = {8287, 8202},
+ ["NoBreak"] = 8288,
+ ["ApplyFunction"] = 8289,
+ ["af"] = 8289,
+ ["InvisibleTimes"] = 8290,
+ ["it"] = 8290,
+ ["InvisibleComma"] = 8291,
+ ["ic"] = 8291,
+ ["euro"] = 8364,
+ ["TripleDot"] = 8411,
+ ["tdot"] = 8411,
+ ["DotDot"] = 8412,
+ ["Copf"] = 8450,
+ ["complexes"] = 8450,
+ ["incare"] = 8453,
+ ["gscr"] = 8458,
+ ["HilbertSpace"] = 8459,
+ ["Hscr"] = 8459,
+ ["hamilt"] = 8459,
+ ["Hfr"] = 8460,
+ ["Poincareplane"] = 8460,
+ ["Hopf"] = 8461,
+ ["quaternions"] = 8461,
+ ["planckh"] = 8462,
+ ["hbar"] = 8463,
+ ["hslash"] = 8463,
+ ["planck"] = 8463,
+ ["plankv"] = 8463,
+ ["Iscr"] = 8464,
+ ["imagline"] = 8464,
+ ["Ifr"] = 8465,
+ ["Im"] = 8465,
+ ["image"] = 8465,
+ ["imagpart"] = 8465,
+ ["Laplacetrf"] = 8466,
+ ["Lscr"] = 8466,
+ ["lagran"] = 8466,
+ ["ell"] = 8467,
+ ["Nopf"] = 8469,
+ ["naturals"] = 8469,
+ ["numero"] = 8470,
+ ["copysr"] = 8471,
+ ["weierp"] = 8472,
+ ["wp"] = 8472,
+ ["Popf"] = 8473,
+ ["primes"] = 8473,
+ ["Qopf"] = 8474,
+ ["rationals"] = 8474,
+ ["Rscr"] = 8475,
+ ["realine"] = 8475,
+ ["Re"] = 8476,
+ ["Rfr"] = 8476,
+ ["real"] = 8476,
+ ["realpart"] = 8476,
+ ["Ropf"] = 8477,
+ ["reals"] = 8477,
+ ["rx"] = 8478,
+ ["TRADE"] = 8482,
+ ["trade"] = 8482,
+ ["Zopf"] = 8484,
+ ["integers"] = 8484,
+ ["mho"] = 8487,
+ ["Zfr"] = 8488,
+ ["zeetrf"] = 8488,
+ ["iiota"] = 8489,
+ ["Bernoullis"] = 8492,
+ ["Bscr"] = 8492,
+ ["bernou"] = 8492,
+ ["Cayleys"] = 8493,
+ ["Cfr"] = 8493,
+ ["escr"] = 8495,
+ ["Escr"] = 8496,
+ ["expectation"] = 8496,
+ ["Fouriertrf"] = 8497,
+ ["Fscr"] = 8497,
+ ["Mellintrf"] = 8499,
+ ["Mscr"] = 8499,
+ ["phmmat"] = 8499,
+ ["order"] = 8500,
+ ["orderof"] = 8500,
+ ["oscr"] = 8500,
+ ["alefsym"] = 8501,
+ ["aleph"] = 8501,
+ ["beth"] = 8502,
+ ["gimel"] = 8503,
+ ["daleth"] = 8504,
+ ["CapitalDifferentialD"] = 8517,
+ ["DD"] = 8517,
+ ["DifferentialD"] = 8518,
+ ["dd"] = 8518,
+ ["ExponentialE"] = 8519,
+ ["ee"] = 8519,
+ ["exponentiale"] = 8519,
+ ["ImaginaryI"] = 8520,
+ ["ii"] = 8520,
+ ["frac13"] = 8531,
+ ["frac23"] = 8532,
+ ["frac15"] = 8533,
+ ["frac25"] = 8534,
+ ["frac35"] = 8535,
+ ["frac45"] = 8536,
+ ["frac16"] = 8537,
+ ["frac56"] = 8538,
+ ["frac18"] = 8539,
+ ["frac38"] = 8540,
+ ["frac58"] = 8541,
+ ["frac78"] = 8542,
+ ["LeftArrow"] = 8592,
+ ["ShortLeftArrow"] = 8592,
+ ["larr"] = 8592,
+ ["leftarrow"] = 8592,
+ ["slarr"] = 8592,
+ ["ShortUpArrow"] = 8593,
+ ["UpArrow"] = 8593,
+ ["uarr"] = 8593,
+ ["uparrow"] = 8593,
+ ["RightArrow"] = 8594,
+ ["ShortRightArrow"] = 8594,
+ ["rarr"] = 8594,
+ ["rightarrow"] = 8594,
+ ["srarr"] = 8594,
+ ["DownArrow"] = 8595,
+ ["ShortDownArrow"] = 8595,
+ ["darr"] = 8595,
+ ["downarrow"] = 8595,
+ ["LeftRightArrow"] = 8596,
+ ["harr"] = 8596,
+ ["leftrightarrow"] = 8596,
+ ["UpDownArrow"] = 8597,
+ ["updownarrow"] = 8597,
+ ["varr"] = 8597,
+ ["UpperLeftArrow"] = 8598,
+ ["nwarr"] = 8598,
+ ["nwarrow"] = 8598,
+ ["UpperRightArrow"] = 8599,
+ ["nearr"] = 8599,
+ ["nearrow"] = 8599,
+ ["LowerRightArrow"] = 8600,
+ ["searr"] = 8600,
+ ["searrow"] = 8600,
+ ["LowerLeftArrow"] = 8601,
+ ["swarr"] = 8601,
+ ["swarrow"] = 8601,
+ ["nlarr"] = 8602,
+ ["nleftarrow"] = 8602,
+ ["nrarr"] = 8603,
+ ["nrightarrow"] = 8603,
+ ["nrarrw"] = {8605, 824},
+ ["rarrw"] = 8605,
+ ["rightsquigarrow"] = 8605,
+ ["Larr"] = 8606,
+ ["twoheadleftarrow"] = 8606,
+ ["Uarr"] = 8607,
+ ["Rarr"] = 8608,
+ ["twoheadrightarrow"] = 8608,
+ ["Darr"] = 8609,
+ ["larrtl"] = 8610,
+ ["leftarrowtail"] = 8610,
+ ["rarrtl"] = 8611,
+ ["rightarrowtail"] = 8611,
+ ["LeftTeeArrow"] = 8612,
+ ["mapstoleft"] = 8612,
+ ["UpTeeArrow"] = 8613,
+ ["mapstoup"] = 8613,
+ ["RightTeeArrow"] = 8614,
+ ["map"] = 8614,
+ ["mapsto"] = 8614,
+ ["DownTeeArrow"] = 8615,
+ ["mapstodown"] = 8615,
+ ["hookleftarrow"] = 8617,
+ ["larrhk"] = 8617,
+ ["hookrightarrow"] = 8618,
+ ["rarrhk"] = 8618,
+ ["larrlp"] = 8619,
+ ["looparrowleft"] = 8619,
+ ["looparrowright"] = 8620,
+ ["rarrlp"] = 8620,
+ ["harrw"] = 8621,
+ ["leftrightsquigarrow"] = 8621,
+ ["nharr"] = 8622,
+ ["nleftrightarrow"] = 8622,
+ ["Lsh"] = 8624,
+ ["lsh"] = 8624,
+ ["Rsh"] = 8625,
+ ["rsh"] = 8625,
+ ["ldsh"] = 8626,
+ ["rdsh"] = 8627,
+ ["crarr"] = 8629,
+ ["cularr"] = 8630,
+ ["curvearrowleft"] = 8630,
+ ["curarr"] = 8631,
+ ["curvearrowright"] = 8631,
+ ["circlearrowleft"] = 8634,
+ ["olarr"] = 8634,
+ ["circlearrowright"] = 8635,
+ ["orarr"] = 8635,
+ ["LeftVector"] = 8636,
+ ["leftharpoonup"] = 8636,
+ ["lharu"] = 8636,
+ ["DownLeftVector"] = 8637,
+ ["leftharpoondown"] = 8637,
+ ["lhard"] = 8637,
+ ["RightUpVector"] = 8638,
+ ["uharr"] = 8638,
+ ["upharpoonright"] = 8638,
+ ["LeftUpVector"] = 8639,
+ ["uharl"] = 8639,
+ ["upharpoonleft"] = 8639,
+ ["RightVector"] = 8640,
+ ["rharu"] = 8640,
+ ["rightharpoonup"] = 8640,
+ ["DownRightVector"] = 8641,
+ ["rhard"] = 8641,
+ ["rightharpoondown"] = 8641,
+ ["RightDownVector"] = 8642,
+ ["dharr"] = 8642,
+ ["downharpoonright"] = 8642,
+ ["LeftDownVector"] = 8643,
+ ["dharl"] = 8643,
+ ["downharpoonleft"] = 8643,
+ ["RightArrowLeftArrow"] = 8644,
+ ["rightleftarrows"] = 8644,
+ ["rlarr"] = 8644,
+ ["UpArrowDownArrow"] = 8645,
+ ["udarr"] = 8645,
+ ["LeftArrowRightArrow"] = 8646,
+ ["leftrightarrows"] = 8646,
+ ["lrarr"] = 8646,
+ ["leftleftarrows"] = 8647,
+ ["llarr"] = 8647,
+ ["upuparrows"] = 8648,
+ ["uuarr"] = 8648,
+ ["rightrightarrows"] = 8649,
+ ["rrarr"] = 8649,
+ ["ddarr"] = 8650,
+ ["downdownarrows"] = 8650,
+ ["ReverseEquilibrium"] = 8651,
+ ["leftrightharpoons"] = 8651,
+ ["lrhar"] = 8651,
+ ["Equilibrium"] = 8652,
+ ["rightleftharpoons"] = 8652,
+ ["rlhar"] = 8652,
+ ["nLeftarrow"] = 8653,
+ ["nlArr"] = 8653,
+ ["nLeftrightarrow"] = 8654,
+ ["nhArr"] = 8654,
+ ["nRightarrow"] = 8655,
+ ["nrArr"] = 8655,
+ ["DoubleLeftArrow"] = 8656,
+ ["Leftarrow"] = 8656,
+ ["lArr"] = 8656,
+ ["DoubleUpArrow"] = 8657,
+ ["Uparrow"] = 8657,
+ ["uArr"] = 8657,
+ ["DoubleRightArrow"] = 8658,
+ ["Implies"] = 8658,
+ ["Rightarrow"] = 8658,
+ ["rArr"] = 8658,
+ ["DoubleDownArrow"] = 8659,
+ ["Downarrow"] = 8659,
+ ["dArr"] = 8659,
+ ["DoubleLeftRightArrow"] = 8660,
+ ["Leftrightarrow"] = 8660,
+ ["hArr"] = 8660,
+ ["iff"] = 8660,
+ ["DoubleUpDownArrow"] = 8661,
+ ["Updownarrow"] = 8661,
+ ["vArr"] = 8661,
+ ["nwArr"] = 8662,
+ ["neArr"] = 8663,
+ ["seArr"] = 8664,
+ ["swArr"] = 8665,
+ ["Lleftarrow"] = 8666,
+ ["lAarr"] = 8666,
+ ["Rrightarrow"] = 8667,
+ ["rAarr"] = 8667,
+ ["zigrarr"] = 8669,
+ ["LeftArrowBar"] = 8676,
+ ["larrb"] = 8676,
+ ["RightArrowBar"] = 8677,
+ ["rarrb"] = 8677,
+ ["DownArrowUpArrow"] = 8693,
+ ["duarr"] = 8693,
+ ["loarr"] = 8701,
+ ["roarr"] = 8702,
+ ["hoarr"] = 8703,
+ ["ForAll"] = 8704,
+ ["forall"] = 8704,
+ ["comp"] = 8705,
+ ["complement"] = 8705,
+ ["PartialD"] = 8706,
+ ["npart"] = {8706, 824},
+ ["part"] = 8706,
+ ["Exists"] = 8707,
+ ["exist"] = 8707,
+ ["NotExists"] = 8708,
+ ["nexist"] = 8708,
+ ["nexists"] = 8708,
+ ["empty"] = 8709,
+ ["emptyset"] = 8709,
+ ["emptyv"] = 8709,
+ ["varnothing"] = 8709,
+ ["Del"] = 8711,
+ ["nabla"] = 8711,
+ ["Element"] = 8712,
+ ["in"] = 8712,
+ ["isin"] = 8712,
+ ["isinv"] = 8712,
+ ["NotElement"] = 8713,
+ ["notin"] = 8713,
+ ["notinva"] = 8713,
+ ["ReverseElement"] = 8715,
+ ["SuchThat"] = 8715,
+ ["ni"] = 8715,
+ ["niv"] = 8715,
+ ["NotReverseElement"] = 8716,
+ ["notni"] = 8716,
+ ["notniva"] = 8716,
+ ["Product"] = 8719,
+ ["prod"] = 8719,
+ ["Coproduct"] = 8720,
+ ["coprod"] = 8720,
+ ["Sum"] = 8721,
+ ["sum"] = 8721,
+ ["minus"] = 8722,
+ ["MinusPlus"] = 8723,
+ ["mnplus"] = 8723,
+ ["mp"] = 8723,
+ ["dotplus"] = 8724,
+ ["plusdo"] = 8724,
+ ["Backslash"] = 8726,
+ ["setminus"] = 8726,
+ ["setmn"] = 8726,
+ ["smallsetminus"] = 8726,
+ ["ssetmn"] = 8726,
+ ["lowast"] = 8727,
+ ["SmallCircle"] = 8728,
+ ["compfn"] = 8728,
+ ["Sqrt"] = 8730,
+ ["radic"] = 8730,
+ ["Proportional"] = 8733,
+ ["prop"] = 8733,
+ ["propto"] = 8733,
+ ["varpropto"] = 8733,
+ ["vprop"] = 8733,
+ ["infin"] = 8734,
+ ["angrt"] = 8735,
+ ["ang"] = 8736,
+ ["angle"] = 8736,
+ ["nang"] = {8736, 8402},
+ ["angmsd"] = 8737,
+ ["measuredangle"] = 8737,
+ ["angsph"] = 8738,
+ ["VerticalBar"] = 8739,
+ ["mid"] = 8739,
+ ["shortmid"] = 8739,
+ ["smid"] = 8739,
+ ["NotVerticalBar"] = 8740,
+ ["nmid"] = 8740,
+ ["nshortmid"] = 8740,
+ ["nsmid"] = 8740,
+ ["DoubleVerticalBar"] = 8741,
+ ["par"] = 8741,
+ ["parallel"] = 8741,
+ ["shortparallel"] = 8741,
+ ["spar"] = 8741,
+ ["NotDoubleVerticalBar"] = 8742,
+ ["npar"] = 8742,
+ ["nparallel"] = 8742,
+ ["nshortparallel"] = 8742,
+ ["nspar"] = 8742,
+ ["and"] = 8743,
+ ["wedge"] = 8743,
+ ["or"] = 8744,
+ ["vee"] = 8744,
+ ["cap"] = 8745,
+ ["caps"] = {8745, 65024},
+ ["cup"] = 8746,
+ ["cups"] = {8746, 65024},
+ ["Integral"] = 8747,
+ ["int"] = 8747,
+ ["Int"] = 8748,
+ ["iiint"] = 8749,
+ ["tint"] = 8749,
+ ["ContourIntegral"] = 8750,
+ ["conint"] = 8750,
+ ["oint"] = 8750,
+ ["Conint"] = 8751,
+ ["DoubleContourIntegral"] = 8751,
+ ["Cconint"] = 8752,
+ ["cwint"] = 8753,
+ ["ClockwiseContourIntegral"] = 8754,
+ ["cwconint"] = 8754,
+ ["CounterClockwiseContourIntegral"] = 8755,
+ ["awconint"] = 8755,
+ ["Therefore"] = 8756,
+ ["there4"] = 8756,
+ ["therefore"] = 8756,
+ ["Because"] = 8757,
+ ["becaus"] = 8757,
+ ["because"] = 8757,
+ ["ratio"] = 8758,
+ ["Colon"] = 8759,
+ ["Proportion"] = 8759,
+ ["dotminus"] = 8760,
+ ["minusd"] = 8760,
+ ["mDDot"] = 8762,
+ ["homtht"] = 8763,
+ ["Tilde"] = 8764,
+ ["nvsim"] = {8764, 8402},
+ ["sim"] = 8764,
+ ["thicksim"] = 8764,
+ ["thksim"] = 8764,
+ ["backsim"] = 8765,
+ ["bsim"] = 8765,
+ ["race"] = {8765, 817},
+ ["ac"] = 8766,
+ ["acE"] = {8766, 819},
+ ["mstpos"] = 8766,
+ ["acd"] = 8767,
+ ["VerticalTilde"] = 8768,
+ ["wr"] = 8768,
+ ["wreath"] = 8768,
+ ["NotTilde"] = 8769,
+ ["nsim"] = 8769,
+ ["EqualTilde"] = 8770,
+ ["NotEqualTilde"] = {8770, 824},
+ ["eqsim"] = 8770,
+ ["esim"] = 8770,
+ ["nesim"] = {8770, 824},
+ ["TildeEqual"] = 8771,
+ ["sime"] = 8771,
+ ["simeq"] = 8771,
+ ["NotTildeEqual"] = 8772,
+ ["nsime"] = 8772,
+ ["nsimeq"] = 8772,
+ ["TildeFullEqual"] = 8773,
+ ["cong"] = 8773,
+ ["simne"] = 8774,
+ ["NotTildeFullEqual"] = 8775,
+ ["ncong"] = 8775,
+ ["TildeTilde"] = 8776,
+ ["ap"] = 8776,
+ ["approx"] = 8776,
+ ["asymp"] = 8776,
+ ["thickapprox"] = 8776,
+ ["thkap"] = 8776,
+ ["NotTildeTilde"] = 8777,
+ ["nap"] = 8777,
+ ["napprox"] = 8777,
+ ["ape"] = 8778,
+ ["approxeq"] = 8778,
+ ["apid"] = 8779,
+ ["napid"] = {8779, 824},
+ ["backcong"] = 8780,
+ ["bcong"] = 8780,
+ ["CupCap"] = 8781,
+ ["asympeq"] = 8781,
+ ["nvap"] = {8781, 8402},
+ ["Bumpeq"] = 8782,
+ ["HumpDownHump"] = 8782,
+ ["NotHumpDownHump"] = {8782, 824},
+ ["bump"] = 8782,
+ ["nbump"] = {8782, 824},
+ ["HumpEqual"] = 8783,
+ ["NotHumpEqual"] = {8783, 824},
+ ["bumpe"] = 8783,
+ ["bumpeq"] = 8783,
+ ["nbumpe"] = {8783, 824},
+ ["DotEqual"] = 8784,
+ ["doteq"] = 8784,
+ ["esdot"] = 8784,
+ ["nedot"] = {8784, 824},
+ ["doteqdot"] = 8785,
+ ["eDot"] = 8785,
+ ["efDot"] = 8786,
+ ["fallingdotseq"] = 8786,
+ ["erDot"] = 8787,
+ ["risingdotseq"] = 8787,
+ ["Assign"] = 8788,
+ ["colone"] = 8788,
+ ["coloneq"] = 8788,
+ ["ecolon"] = 8789,
+ ["eqcolon"] = 8789,
+ ["ecir"] = 8790,
+ ["eqcirc"] = 8790,
+ ["circeq"] = 8791,
+ ["cire"] = 8791,
+ ["wedgeq"] = 8793,
+ ["veeeq"] = 8794,
+ ["triangleq"] = 8796,
+ ["trie"] = 8796,
+ ["equest"] = 8799,
+ ["questeq"] = 8799,
+ ["NotEqual"] = 8800,
+ ["ne"] = 8800,
+ ["Congruent"] = 8801,
+ ["bnequiv"] = {8801, 8421},
+ ["equiv"] = 8801,
+ ["NotCongruent"] = 8802,
+ ["nequiv"] = 8802,
+ ["le"] = 8804,
+ ["leq"] = 8804,
+ ["nvle"] = {8804, 8402},
+ ["GreaterEqual"] = 8805,
+ ["ge"] = 8805,
+ ["geq"] = 8805,
+ ["nvge"] = {8805, 8402},
+ ["LessFullEqual"] = 8806,
+ ["lE"] = 8806,
+ ["leqq"] = 8806,
+ ["nlE"] = {8806, 824},
+ ["nleqq"] = {8806, 824},
+ ["GreaterFullEqual"] = 8807,
+ ["NotGreaterFullEqual"] = {8807, 824},
+ ["gE"] = 8807,
+ ["geqq"] = 8807,
+ ["ngE"] = {8807, 824},
+ ["ngeqq"] = {8807, 824},
+ ["lnE"] = 8808,
+ ["lneqq"] = 8808,
+ ["lvertneqq"] = {8808, 65024},
+ ["lvnE"] = {8808, 65024},
+ ["gnE"] = 8809,
+ ["gneqq"] = 8809,
+ ["gvertneqq"] = {8809, 65024},
+ ["gvnE"] = {8809, 65024},
+ ["Lt"] = 8810,
+ ["NestedLessLess"] = 8810,
+ ["NotLessLess"] = {8810, 824},
+ ["ll"] = 8810,
+ ["nLt"] = {8810, 8402},
+ ["nLtv"] = {8810, 824},
+ ["Gt"] = 8811,
+ ["NestedGreaterGreater"] = 8811,
+ ["NotGreaterGreater"] = {8811, 824},
+ ["gg"] = 8811,
+ ["nGt"] = {8811, 8402},
+ ["nGtv"] = {8811, 824},
+ ["between"] = 8812,
+ ["twixt"] = 8812,
+ ["NotCupCap"] = 8813,
+ ["NotLess"] = 8814,
+ ["nless"] = 8814,
+ ["nlt"] = 8814,
+ ["NotGreater"] = 8815,
+ ["ngt"] = 8815,
+ ["ngtr"] = 8815,
+ ["NotLessEqual"] = 8816,
+ ["nle"] = 8816,
+ ["nleq"] = 8816,
+ ["NotGreaterEqual"] = 8817,
+ ["nge"] = 8817,
+ ["ngeq"] = 8817,
+ ["LessTilde"] = 8818,
+ ["lesssim"] = 8818,
+ ["lsim"] = 8818,
+ ["GreaterTilde"] = 8819,
+ ["gsim"] = 8819,
+ ["gtrsim"] = 8819,
+ ["NotLessTilde"] = 8820,
+ ["nlsim"] = 8820,
+ ["NotGreaterTilde"] = 8821,
+ ["ngsim"] = 8821,
+ ["LessGreater"] = 8822,
+ ["lessgtr"] = 8822,
+ ["lg"] = 8822,
+ ["GreaterLess"] = 8823,
+ ["gl"] = 8823,
+ ["gtrless"] = 8823,
+ ["NotLessGreater"] = 8824,
+ ["ntlg"] = 8824,
+ ["NotGreaterLess"] = 8825,
+ ["ntgl"] = 8825,
+ ["Precedes"] = 8826,
+ ["pr"] = 8826,
+ ["prec"] = 8826,
+ ["Succeeds"] = 8827,
+ ["sc"] = 8827,
+ ["succ"] = 8827,
+ ["PrecedesSlantEqual"] = 8828,
+ ["prcue"] = 8828,
+ ["preccurlyeq"] = 8828,
+ ["SucceedsSlantEqual"] = 8829,
+ ["sccue"] = 8829,
+ ["succcurlyeq"] = 8829,
+ ["PrecedesTilde"] = 8830,
+ ["precsim"] = 8830,
+ ["prsim"] = 8830,
+ ["NotSucceedsTilde"] = {8831, 824},
+ ["SucceedsTilde"] = 8831,
+ ["scsim"] = 8831,
+ ["succsim"] = 8831,
+ ["NotPrecedes"] = 8832,
+ ["npr"] = 8832,
+ ["nprec"] = 8832,
+ ["NotSucceeds"] = 8833,
+ ["nsc"] = 8833,
+ ["nsucc"] = 8833,
+ ["NotSubset"] = {8834, 8402},
+ ["nsubset"] = {8834, 8402},
+ ["sub"] = 8834,
+ ["subset"] = 8834,
+ ["vnsub"] = {8834, 8402},
+ ["NotSuperset"] = {8835, 8402},
+ ["Superset"] = 8835,
+ ["nsupset"] = {8835, 8402},
+ ["sup"] = 8835,
+ ["supset"] = 8835,
+ ["vnsup"] = {8835, 8402},
+ ["nsub"] = 8836,
+ ["nsup"] = 8837,
+ ["SubsetEqual"] = 8838,
+ ["sube"] = 8838,
+ ["subseteq"] = 8838,
+ ["SupersetEqual"] = 8839,
+ ["supe"] = 8839,
+ ["supseteq"] = 8839,
+ ["NotSubsetEqual"] = 8840,
+ ["nsube"] = 8840,
+ ["nsubseteq"] = 8840,
+ ["NotSupersetEqual"] = 8841,
+ ["nsupe"] = 8841,
+ ["nsupseteq"] = 8841,
+ ["subne"] = 8842,
+ ["subsetneq"] = 8842,
+ ["varsubsetneq"] = {8842, 65024},
+ ["vsubne"] = {8842, 65024},
+ ["supne"] = 8843,
+ ["supsetneq"] = 8843,
+ ["varsupsetneq"] = {8843, 65024},
+ ["vsupne"] = {8843, 65024},
+ ["cupdot"] = 8845,
+ ["UnionPlus"] = 8846,
+ ["uplus"] = 8846,
+ ["NotSquareSubset"] = {8847, 824},
+ ["SquareSubset"] = 8847,
+ ["sqsub"] = 8847,
+ ["sqsubset"] = 8847,
+ ["NotSquareSuperset"] = {8848, 824},
+ ["SquareSuperset"] = 8848,
+ ["sqsup"] = 8848,
+ ["sqsupset"] = 8848,
+ ["SquareSubsetEqual"] = 8849,
+ ["sqsube"] = 8849,
+ ["sqsubseteq"] = 8849,
+ ["SquareSupersetEqual"] = 8850,
+ ["sqsupe"] = 8850,
+ ["sqsupseteq"] = 8850,
+ ["SquareIntersection"] = 8851,
+ ["sqcap"] = 8851,
+ ["sqcaps"] = {8851, 65024},
+ ["SquareUnion"] = 8852,
+ ["sqcup"] = 8852,
+ ["sqcups"] = {8852, 65024},
+ ["CirclePlus"] = 8853,
+ ["oplus"] = 8853,
+ ["CircleMinus"] = 8854,
+ ["ominus"] = 8854,
+ ["CircleTimes"] = 8855,
+ ["otimes"] = 8855,
+ ["osol"] = 8856,
+ ["CircleDot"] = 8857,
+ ["odot"] = 8857,
+ ["circledcirc"] = 8858,
+ ["ocir"] = 8858,
+ ["circledast"] = 8859,
+ ["oast"] = 8859,
+ ["circleddash"] = 8861,
+ ["odash"] = 8861,
+ ["boxplus"] = 8862,
+ ["plusb"] = 8862,
+ ["boxminus"] = 8863,
+ ["minusb"] = 8863,
+ ["boxtimes"] = 8864,
+ ["timesb"] = 8864,
+ ["dotsquare"] = 8865,
+ ["sdotb"] = 8865,
+ ["RightTee"] = 8866,
+ ["vdash"] = 8866,
+ ["LeftTee"] = 8867,
+ ["dashv"] = 8867,
+ ["DownTee"] = 8868,
+ ["top"] = 8868,
+ ["UpTee"] = 8869,
+ ["bot"] = 8869,
+ ["bottom"] = 8869,
+ ["perp"] = 8869,
+ ["models"] = 8871,
+ ["DoubleRightTee"] = 8872,
+ ["vDash"] = 8872,
+ ["Vdash"] = 8873,
+ ["Vvdash"] = 8874,
+ ["VDash"] = 8875,
+ ["nvdash"] = 8876,
+ ["nvDash"] = 8877,
+ ["nVdash"] = 8878,
+ ["nVDash"] = 8879,
+ ["prurel"] = 8880,
+ ["LeftTriangle"] = 8882,
+ ["vartriangleleft"] = 8882,
+ ["vltri"] = 8882,
+ ["RightTriangle"] = 8883,
+ ["vartriangleright"] = 8883,
+ ["vrtri"] = 8883,
+ ["LeftTriangleEqual"] = 8884,
+ ["ltrie"] = 8884,
+ ["nvltrie"] = {8884, 8402},
+ ["trianglelefteq"] = 8884,
+ ["RightTriangleEqual"] = 8885,
+ ["nvrtrie"] = {8885, 8402},
+ ["rtrie"] = 8885,
+ ["trianglerighteq"] = 8885,
+ ["origof"] = 8886,
+ ["imof"] = 8887,
+ ["multimap"] = 8888,
+ ["mumap"] = 8888,
+ ["hercon"] = 8889,
+ ["intcal"] = 8890,
+ ["intercal"] = 8890,
+ ["veebar"] = 8891,
+ ["barvee"] = 8893,
+ ["angrtvb"] = 8894,
+ ["lrtri"] = 8895,
+ ["Wedge"] = 8896,
+ ["bigwedge"] = 8896,
+ ["xwedge"] = 8896,
+ ["Vee"] = 8897,
+ ["bigvee"] = 8897,
+ ["xvee"] = 8897,
+ ["Intersection"] = 8898,
+ ["bigcap"] = 8898,
+ ["xcap"] = 8898,
+ ["Union"] = 8899,
+ ["bigcup"] = 8899,
+ ["xcup"] = 8899,
+ ["Diamond"] = 8900,
+ ["diam"] = 8900,
+ ["diamond"] = 8900,
+ ["sdot"] = 8901,
+ ["Star"] = 8902,
+ ["sstarf"] = 8902,
+ ["divideontimes"] = 8903,
+ ["divonx"] = 8903,
+ ["bowtie"] = 8904,
+ ["ltimes"] = 8905,
+ ["rtimes"] = 8906,
+ ["leftthreetimes"] = 8907,
+ ["lthree"] = 8907,
+ ["rightthreetimes"] = 8908,
+ ["rthree"] = 8908,
+ ["backsimeq"] = 8909,
+ ["bsime"] = 8909,
+ ["curlyvee"] = 8910,
+ ["cuvee"] = 8910,
+ ["curlywedge"] = 8911,
+ ["cuwed"] = 8911,
+ ["Sub"] = 8912,
+ ["Subset"] = 8912,
+ ["Sup"] = 8913,
+ ["Supset"] = 8913,
+ ["Cap"] = 8914,
+ ["Cup"] = 8915,
+ ["fork"] = 8916,
+ ["pitchfork"] = 8916,
+ ["epar"] = 8917,
+ ["lessdot"] = 8918,
+ ["ltdot"] = 8918,
+ ["gtdot"] = 8919,
+ ["gtrdot"] = 8919,
+ ["Ll"] = 8920,
+ ["nLl"] = {8920, 824},
+ ["Gg"] = 8921,
+ ["ggg"] = 8921,
+ ["nGg"] = {8921, 824},
+ ["LessEqualGreater"] = 8922,
+ ["leg"] = 8922,
+ ["lesg"] = {8922, 65024},
+ ["lesseqgtr"] = 8922,
+ ["GreaterEqualLess"] = 8923,
+ ["gel"] = 8923,
+ ["gesl"] = {8923, 65024},
+ ["gtreqless"] = 8923,
+ ["cuepr"] = 8926,
+ ["curlyeqprec"] = 8926,
+ ["cuesc"] = 8927,
+ ["curlyeqsucc"] = 8927,
+ ["NotPrecedesSlantEqual"] = 8928,
+ ["nprcue"] = 8928,
+ ["NotSucceedsSlantEqual"] = 8929,
+ ["nsccue"] = 8929,
+ ["NotSquareSubsetEqual"] = 8930,
+ ["nsqsube"] = 8930,
+ ["NotSquareSupersetEqual"] = 8931,
+ ["nsqsupe"] = 8931,
+ ["lnsim"] = 8934,
+ ["gnsim"] = 8935,
+ ["precnsim"] = 8936,
+ ["prnsim"] = 8936,
+ ["scnsim"] = 8937,
+ ["succnsim"] = 8937,
+ ["NotLeftTriangle"] = 8938,
+ ["nltri"] = 8938,
+ ["ntriangleleft"] = 8938,
+ ["NotRightTriangle"] = 8939,
+ ["nrtri"] = 8939,
+ ["ntriangleright"] = 8939,
+ ["NotLeftTriangleEqual"] = 8940,
+ ["nltrie"] = 8940,
+ ["ntrianglelefteq"] = 8940,
+ ["NotRightTriangleEqual"] = 8941,
+ ["nrtrie"] = 8941,
+ ["ntrianglerighteq"] = 8941,
+ ["vellip"] = 8942,
+ ["ctdot"] = 8943,
+ ["utdot"] = 8944,
+ ["dtdot"] = 8945,
+ ["disin"] = 8946,
+ ["isinsv"] = 8947,
+ ["isins"] = 8948,
+ ["isindot"] = 8949,
+ ["notindot"] = {8949, 824},
+ ["notinvc"] = 8950,
+ ["notinvb"] = 8951,
+ ["isinE"] = 8953,
+ ["notinE"] = {8953, 824},
+ ["nisd"] = 8954,
+ ["xnis"] = 8955,
+ ["nis"] = 8956,
+ ["notnivc"] = 8957,
+ ["notnivb"] = 8958,
+ ["barwed"] = 8965,
+ ["barwedge"] = 8965,
+ ["Barwed"] = 8966,
+ ["doublebarwedge"] = 8966,
+ ["LeftCeiling"] = 8968,
+ ["lceil"] = 8968,
+ ["RightCeiling"] = 8969,
+ ["rceil"] = 8969,
+ ["LeftFloor"] = 8970,
+ ["lfloor"] = 8970,
+ ["RightFloor"] = 8971,
+ ["rfloor"] = 8971,
+ ["drcrop"] = 8972,
+ ["dlcrop"] = 8973,
+ ["urcrop"] = 8974,
+ ["ulcrop"] = 8975,
+ ["bnot"] = 8976,
+ ["profline"] = 8978,
+ ["profsurf"] = 8979,
+ ["telrec"] = 8981,
+ ["target"] = 8982,
+ ["ulcorn"] = 8988,
+ ["ulcorner"] = 8988,
+ ["urcorn"] = 8989,
+ ["urcorner"] = 8989,
+ ["dlcorn"] = 8990,
+ ["llcorner"] = 8990,
+ ["drcorn"] = 8991,
+ ["lrcorner"] = 8991,
+ ["frown"] = 8994,
+ ["sfrown"] = 8994,
+ ["smile"] = 8995,
+ ["ssmile"] = 8995,
+ ["cylcty"] = 9005,
+ ["profalar"] = 9006,
+ ["topbot"] = 9014,
+ ["ovbar"] = 9021,
+ ["solbar"] = 9023,
+ ["angzarr"] = 9084,
+ ["lmoust"] = 9136,
+ ["lmoustache"] = 9136,
+ ["rmoust"] = 9137,
+ ["rmoustache"] = 9137,
+ ["OverBracket"] = 9140,
+ ["tbrk"] = 9140,
+ ["UnderBracket"] = 9141,
+ ["bbrk"] = 9141,
+ ["bbrktbrk"] = 9142,
+ ["OverParenthesis"] = 9180,
+ ["UnderParenthesis"] = 9181,
+ ["OverBrace"] = 9182,
+ ["UnderBrace"] = 9183,
+ ["trpezium"] = 9186,
+ ["elinters"] = 9191,
+ ["blank"] = 9251,
+ ["circledS"] = 9416,
+ ["oS"] = 9416,
+ ["HorizontalLine"] = 9472,
+ ["boxh"] = 9472,
+ ["boxv"] = 9474,
+ ["boxdr"] = 9484,
+ ["boxdl"] = 9488,
+ ["boxur"] = 9492,
+ ["boxul"] = 9496,
+ ["boxvr"] = 9500,
+ ["boxvl"] = 9508,
+ ["boxhd"] = 9516,
+ ["boxhu"] = 9524,
+ ["boxvh"] = 9532,
+ ["boxH"] = 9552,
+ ["boxV"] = 9553,
+ ["boxdR"] = 9554,
+ ["boxDr"] = 9555,
+ ["boxDR"] = 9556,
+ ["boxdL"] = 9557,
+ ["boxDl"] = 9558,
+ ["boxDL"] = 9559,
+ ["boxuR"] = 9560,
+ ["boxUr"] = 9561,
+ ["boxUR"] = 9562,
+ ["boxuL"] = 9563,
+ ["boxUl"] = 9564,
+ ["boxUL"] = 9565,
+ ["boxvR"] = 9566,
+ ["boxVr"] = 9567,
+ ["boxVR"] = 9568,
+ ["boxvL"] = 9569,
+ ["boxVl"] = 9570,
+ ["boxVL"] = 9571,
+ ["boxHd"] = 9572,
+ ["boxhD"] = 9573,
+ ["boxHD"] = 9574,
+ ["boxHu"] = 9575,
+ ["boxhU"] = 9576,
+ ["boxHU"] = 9577,
+ ["boxvH"] = 9578,
+ ["boxVh"] = 9579,
+ ["boxVH"] = 9580,
+ ["uhblk"] = 9600,
+ ["lhblk"] = 9604,
+ ["block"] = 9608,
+ ["blk14"] = 9617,
+ ["blk12"] = 9618,
+ ["blk34"] = 9619,
+ ["Square"] = 9633,
+ ["squ"] = 9633,
+ ["square"] = 9633,
+ ["FilledVerySmallSquare"] = 9642,
+ ["blacksquare"] = 9642,
+ ["squarf"] = 9642,
+ ["squf"] = 9642,
+ ["EmptyVerySmallSquare"] = 9643,
+ ["rect"] = 9645,
+ ["marker"] = 9646,
+ ["fltns"] = 9649,
+ ["bigtriangleup"] = 9651,
+ ["xutri"] = 9651,
+ ["blacktriangle"] = 9652,
+ ["utrif"] = 9652,
+ ["triangle"] = 9653,
+ ["utri"] = 9653,
+ ["blacktriangleright"] = 9656,
+ ["rtrif"] = 9656,
+ ["rtri"] = 9657,
+ ["triangleright"] = 9657,
+ ["bigtriangledown"] = 9661,
+ ["xdtri"] = 9661,
+ ["blacktriangledown"] = 9662,
+ ["dtrif"] = 9662,
+ ["dtri"] = 9663,
+ ["triangledown"] = 9663,
+ ["blacktriangleleft"] = 9666,
+ ["ltrif"] = 9666,
+ ["ltri"] = 9667,
+ ["triangleleft"] = 9667,
+ ["loz"] = 9674,
+ ["lozenge"] = 9674,
+ ["cir"] = 9675,
+ ["tridot"] = 9708,
+ ["bigcirc"] = 9711,
+ ["xcirc"] = 9711,
+ ["ultri"] = 9720,
+ ["urtri"] = 9721,
+ ["lltri"] = 9722,
+ ["EmptySmallSquare"] = 9723,
+ ["FilledSmallSquare"] = 9724,
+ ["bigstar"] = 9733,
+ ["starf"] = 9733,
+ ["star"] = 9734,
+ ["phone"] = 9742,
+ ["female"] = 9792,
+ ["male"] = 9794,
+ ["spades"] = 9824,
+ ["spadesuit"] = 9824,
+ ["clubs"] = 9827,
+ ["clubsuit"] = 9827,
+ ["hearts"] = 9829,
+ ["heartsuit"] = 9829,
+ ["diamondsuit"] = 9830,
+ ["diams"] = 9830,
+ ["sung"] = 9834,
+ ["flat"] = 9837,
+ ["natur"] = 9838,
+ ["natural"] = 9838,
+ ["sharp"] = 9839,
+ ["check"] = 10003,
+ ["checkmark"] = 10003,
+ ["cross"] = 10007,
+ ["malt"] = 10016,
+ ["maltese"] = 10016,
+ ["sext"] = 10038,
+ ["VerticalSeparator"] = 10072,
+ ["lbbrk"] = 10098,
+ ["rbbrk"] = 10099,
+ ["bsolhsub"] = 10184,
+ ["suphsol"] = 10185,
+ ["LeftDoubleBracket"] = 10214,
+ ["lobrk"] = 10214,
+ ["RightDoubleBracket"] = 10215,
+ ["robrk"] = 10215,
+ ["LeftAngleBracket"] = 10216,
+ ["lang"] = 10216,
+ ["langle"] = 10216,
+ ["RightAngleBracket"] = 10217,
+ ["rang"] = 10217,
+ ["rangle"] = 10217,
+ ["Lang"] = 10218,
+ ["Rang"] = 10219,
+ ["loang"] = 10220,
+ ["roang"] = 10221,
+ ["LongLeftArrow"] = 10229,
+ ["longleftarrow"] = 10229,
+ ["xlarr"] = 10229,
+ ["LongRightArrow"] = 10230,
+ ["longrightarrow"] = 10230,
+ ["xrarr"] = 10230,
+ ["LongLeftRightArrow"] = 10231,
+ ["longleftrightarrow"] = 10231,
+ ["xharr"] = 10231,
+ ["DoubleLongLeftArrow"] = 10232,
+ ["Longleftarrow"] = 10232,
+ ["xlArr"] = 10232,
+ ["DoubleLongRightArrow"] = 10233,
+ ["Longrightarrow"] = 10233,
+ ["xrArr"] = 10233,
+ ["DoubleLongLeftRightArrow"] = 10234,
+ ["Longleftrightarrow"] = 10234,
+ ["xhArr"] = 10234,
+ ["longmapsto"] = 10236,
+ ["xmap"] = 10236,
+ ["dzigrarr"] = 10239,
+ ["nvlArr"] = 10498,
+ ["nvrArr"] = 10499,
+ ["nvHarr"] = 10500,
+ ["Map"] = 10501,
+ ["lbarr"] = 10508,
+ ["bkarow"] = 10509,
+ ["rbarr"] = 10509,
+ ["lBarr"] = 10510,
+ ["dbkarow"] = 10511,
+ ["rBarr"] = 10511,
+ ["RBarr"] = 10512,
+ ["drbkarow"] = 10512,
+ ["DDotrahd"] = 10513,
+ ["UpArrowBar"] = 10514,
+ ["DownArrowBar"] = 10515,
+ ["Rarrtl"] = 10518,
+ ["latail"] = 10521,
+ ["ratail"] = 10522,
+ ["lAtail"] = 10523,
+ ["rAtail"] = 10524,
+ ["larrfs"] = 10525,
+ ["rarrfs"] = 10526,
+ ["larrbfs"] = 10527,
+ ["rarrbfs"] = 10528,
+ ["nwarhk"] = 10531,
+ ["nearhk"] = 10532,
+ ["hksearow"] = 10533,
+ ["searhk"] = 10533,
+ ["hkswarow"] = 10534,
+ ["swarhk"] = 10534,
+ ["nwnear"] = 10535,
+ ["nesear"] = 10536,
+ ["toea"] = 10536,
+ ["seswar"] = 10537,
+ ["tosa"] = 10537,
+ ["swnwar"] = 10538,
+ ["nrarrc"] = {10547, 824},
+ ["rarrc"] = 10547,
+ ["cudarrr"] = 10549,
+ ["ldca"] = 10550,
+ ["rdca"] = 10551,
+ ["cudarrl"] = 10552,
+ ["larrpl"] = 10553,
+ ["curarrm"] = 10556,
+ ["cularrp"] = 10557,
+ ["rarrpl"] = 10565,
+ ["harrcir"] = 10568,
+ ["Uarrocir"] = 10569,
+ ["lurdshar"] = 10570,
+ ["ldrushar"] = 10571,
+ ["LeftRightVector"] = 10574,
+ ["RightUpDownVector"] = 10575,
+ ["DownLeftRightVector"] = 10576,
+ ["LeftUpDownVector"] = 10577,
+ ["LeftVectorBar"] = 10578,
+ ["RightVectorBar"] = 10579,
+ ["RightUpVectorBar"] = 10580,
+ ["RightDownVectorBar"] = 10581,
+ ["DownLeftVectorBar"] = 10582,
+ ["DownRightVectorBar"] = 10583,
+ ["LeftUpVectorBar"] = 10584,
+ ["LeftDownVectorBar"] = 10585,
+ ["LeftTeeVector"] = 10586,
+ ["RightTeeVector"] = 10587,
+ ["RightUpTeeVector"] = 10588,
+ ["RightDownTeeVector"] = 10589,
+ ["DownLeftTeeVector"] = 10590,
+ ["DownRightTeeVector"] = 10591,
+ ["LeftUpTeeVector"] = 10592,
+ ["LeftDownTeeVector"] = 10593,
+ ["lHar"] = 10594,
+ ["uHar"] = 10595,
+ ["rHar"] = 10596,
+ ["dHar"] = 10597,
+ ["luruhar"] = 10598,
+ ["ldrdhar"] = 10599,
+ ["ruluhar"] = 10600,
+ ["rdldhar"] = 10601,
+ ["lharul"] = 10602,
+ ["llhard"] = 10603,
+ ["rharul"] = 10604,
+ ["lrhard"] = 10605,
+ ["UpEquilibrium"] = 10606,
+ ["udhar"] = 10606,
+ ["ReverseUpEquilibrium"] = 10607,
+ ["duhar"] = 10607,
+ ["RoundImplies"] = 10608,
+ ["erarr"] = 10609,
+ ["simrarr"] = 10610,
+ ["larrsim"] = 10611,
+ ["rarrsim"] = 10612,
+ ["rarrap"] = 10613,
+ ["ltlarr"] = 10614,
+ ["gtrarr"] = 10616,
+ ["subrarr"] = 10617,
+ ["suplarr"] = 10619,
+ ["lfisht"] = 10620,
+ ["rfisht"] = 10621,
+ ["ufisht"] = 10622,
+ ["dfisht"] = 10623,
+ ["lopar"] = 10629,
+ ["ropar"] = 10630,
+ ["lbrke"] = 10635,
+ ["rbrke"] = 10636,
+ ["lbrkslu"] = 10637,
+ ["rbrksld"] = 10638,
+ ["lbrksld"] = 10639,
+ ["rbrkslu"] = 10640,
+ ["langd"] = 10641,
+ ["rangd"] = 10642,
+ ["lparlt"] = 10643,
+ ["rpargt"] = 10644,
+ ["gtlPar"] = 10645,
+ ["ltrPar"] = 10646,
+ ["vzigzag"] = 10650,
+ ["vangrt"] = 10652,
+ ["angrtvbd"] = 10653,
+ ["ange"] = 10660,
+ ["range"] = 10661,
+ ["dwangle"] = 10662,
+ ["uwangle"] = 10663,
+ ["angmsdaa"] = 10664,
+ ["angmsdab"] = 10665,
+ ["angmsdac"] = 10666,
+ ["angmsdad"] = 10667,
+ ["angmsdae"] = 10668,
+ ["angmsdaf"] = 10669,
+ ["angmsdag"] = 10670,
+ ["angmsdah"] = 10671,
+ ["bemptyv"] = 10672,
+ ["demptyv"] = 10673,
+ ["cemptyv"] = 10674,
+ ["raemptyv"] = 10675,
+ ["laemptyv"] = 10676,
+ ["ohbar"] = 10677,
+ ["omid"] = 10678,
+ ["opar"] = 10679,
+ ["operp"] = 10681,
+ ["olcross"] = 10683,
+ ["odsold"] = 10684,
+ ["olcir"] = 10686,
+ ["ofcir"] = 10687,
+ ["olt"] = 10688,
+ ["ogt"] = 10689,
+ ["cirscir"] = 10690,
+ ["cirE"] = 10691,
+ ["solb"] = 10692,
+ ["bsolb"] = 10693,
+ ["boxbox"] = 10697,
+ ["trisb"] = 10701,
+ ["rtriltri"] = 10702,
+ ["LeftTriangleBar"] = 10703,
+ ["NotLeftTriangleBar"] = {10703, 824},
+ ["NotRightTriangleBar"] = {10704, 824},
+ ["RightTriangleBar"] = 10704,
+ ["iinfin"] = 10716,
+ ["infintie"] = 10717,
+ ["nvinfin"] = 10718,
+ ["eparsl"] = 10723,
+ ["smeparsl"] = 10724,
+ ["eqvparsl"] = 10725,
+ ["blacklozenge"] = 10731,
+ ["lozf"] = 10731,
+ ["RuleDelayed"] = 10740,
+ ["dsol"] = 10742,
+ ["bigodot"] = 10752,
+ ["xodot"] = 10752,
+ ["bigoplus"] = 10753,
+ ["xoplus"] = 10753,
+ ["bigotimes"] = 10754,
+ ["xotime"] = 10754,
+ ["biguplus"] = 10756,
+ ["xuplus"] = 10756,
+ ["bigsqcup"] = 10758,
+ ["xsqcup"] = 10758,
+ ["iiiint"] = 10764,
+ ["qint"] = 10764,
+ ["fpartint"] = 10765,
+ ["cirfnint"] = 10768,
+ ["awint"] = 10769,
+ ["rppolint"] = 10770,
+ ["scpolint"] = 10771,
+ ["npolint"] = 10772,
+ ["pointint"] = 10773,
+ ["quatint"] = 10774,
+ ["intlarhk"] = 10775,
+ ["pluscir"] = 10786,
+ ["plusacir"] = 10787,
+ ["simplus"] = 10788,
+ ["plusdu"] = 10789,
+ ["plussim"] = 10790,
+ ["plustwo"] = 10791,
+ ["mcomma"] = 10793,
+ ["minusdu"] = 10794,
+ ["loplus"] = 10797,
+ ["roplus"] = 10798,
+ ["Cross"] = 10799,
+ ["timesd"] = 10800,
+ ["timesbar"] = 10801,
+ ["smashp"] = 10803,
+ ["lotimes"] = 10804,
+ ["rotimes"] = 10805,
+ ["otimesas"] = 10806,
+ ["Otimes"] = 10807,
+ ["odiv"] = 10808,
+ ["triplus"] = 10809,
+ ["triminus"] = 10810,
+ ["tritime"] = 10811,
+ ["intprod"] = 10812,
+ ["iprod"] = 10812,
+ ["amalg"] = 10815,
+ ["capdot"] = 10816,
+ ["ncup"] = 10818,
+ ["ncap"] = 10819,
+ ["capand"] = 10820,
+ ["cupor"] = 10821,
+ ["cupcap"] = 10822,
+ ["capcup"] = 10823,
+ ["cupbrcap"] = 10824,
+ ["capbrcup"] = 10825,
+ ["cupcup"] = 10826,
+ ["capcap"] = 10827,
+ ["ccups"] = 10828,
+ ["ccaps"] = 10829,
+ ["ccupssm"] = 10832,
+ ["And"] = 10835,
+ ["Or"] = 10836,
+ ["andand"] = 10837,
+ ["oror"] = 10838,
+ ["orslope"] = 10839,
+ ["andslope"] = 10840,
+ ["andv"] = 10842,
+ ["orv"] = 10843,
+ ["andd"] = 10844,
+ ["ord"] = 10845,
+ ["wedbar"] = 10847,
+ ["sdote"] = 10854,
+ ["simdot"] = 10858,
+ ["congdot"] = 10861,
+ ["ncongdot"] = {10861, 824},
+ ["easter"] = 10862,
+ ["apacir"] = 10863,
+ ["apE"] = 10864,
+ ["napE"] = {10864, 824},
+ ["eplus"] = 10865,
+ ["pluse"] = 10866,
+ ["Esim"] = 10867,
+ ["Colone"] = 10868,
+ ["Equal"] = 10869,
+ ["ddotseq"] = 10871,
+ ["eDDot"] = 10871,
+ ["equivDD"] = 10872,
+ ["ltcir"] = 10873,
+ ["gtcir"] = 10874,
+ ["ltquest"] = 10875,
+ ["gtquest"] = 10876,
+ ["LessSlantEqual"] = 10877,
+ ["NotLessSlantEqual"] = {10877, 824},
+ ["leqslant"] = 10877,
+ ["les"] = 10877,
+ ["nleqslant"] = {10877, 824},
+ ["nles"] = {10877, 824},
+ ["GreaterSlantEqual"] = 10878,
+ ["NotGreaterSlantEqual"] = {10878, 824},
+ ["geqslant"] = 10878,
+ ["ges"] = 10878,
+ ["ngeqslant"] = {10878, 824},
+ ["nges"] = {10878, 824},
+ ["lesdot"] = 10879,
+ ["gesdot"] = 10880,
+ ["lesdoto"] = 10881,
+ ["gesdoto"] = 10882,
+ ["lesdotor"] = 10883,
+ ["gesdotol"] = 10884,
+ ["lap"] = 10885,
+ ["lessapprox"] = 10885,
+ ["gap"] = 10886,
+ ["gtrapprox"] = 10886,
+ ["lne"] = 10887,
+ ["lneq"] = 10887,
+ ["gne"] = 10888,
+ ["gneq"] = 10888,
+ ["lnap"] = 10889,
+ ["lnapprox"] = 10889,
+ ["gnap"] = 10890,
+ ["gnapprox"] = 10890,
+ ["lEg"] = 10891,
+ ["lesseqqgtr"] = 10891,
+ ["gEl"] = 10892,
+ ["gtreqqless"] = 10892,
+ ["lsime"] = 10893,
+ ["gsime"] = 10894,
+ ["lsimg"] = 10895,
+ ["gsiml"] = 10896,
+ ["lgE"] = 10897,
+ ["glE"] = 10898,
+ ["lesges"] = 10899,
+ ["gesles"] = 10900,
+ ["els"] = 10901,
+ ["eqslantless"] = 10901,
+ ["egs"] = 10902,
+ ["eqslantgtr"] = 10902,
+ ["elsdot"] = 10903,
+ ["egsdot"] = 10904,
+ ["el"] = 10905,
+ ["eg"] = 10906,
+ ["siml"] = 10909,
+ ["simg"] = 10910,
+ ["simlE"] = 10911,
+ ["simgE"] = 10912,
+ ["LessLess"] = 10913,
+ ["NotNestedLessLess"] = {10913, 824},
+ ["GreaterGreater"] = 10914,
+ ["NotNestedGreaterGreater"] = {10914, 824},
+ ["glj"] = 10916,
+ ["gla"] = 10917,
+ ["ltcc"] = 10918,
+ ["gtcc"] = 10919,
+ ["lescc"] = 10920,
+ ["gescc"] = 10921,
+ ["smt"] = 10922,
+ ["lat"] = 10923,
+ ["smte"] = 10924,
+ ["smtes"] = {10924, 65024},
+ ["late"] = 10925,
+ ["lates"] = {10925, 65024},
+ ["bumpE"] = 10926,
+ ["NotPrecedesEqual"] = {10927, 824},
+ ["PrecedesEqual"] = 10927,
+ ["npre"] = {10927, 824},
+ ["npreceq"] = {10927, 824},
+ ["pre"] = 10927,
+ ["preceq"] = 10927,
+ ["NotSucceedsEqual"] = {10928, 824},
+ ["SucceedsEqual"] = 10928,
+ ["nsce"] = {10928, 824},
+ ["nsucceq"] = {10928, 824},
+ ["sce"] = 10928,
+ ["succeq"] = 10928,
+ ["prE"] = 10931,
+ ["scE"] = 10932,
+ ["precneqq"] = 10933,
+ ["prnE"] = 10933,
+ ["scnE"] = 10934,
+ ["succneqq"] = 10934,
+ ["prap"] = 10935,
+ ["precapprox"] = 10935,
+ ["scap"] = 10936,
+ ["succapprox"] = 10936,
+ ["precnapprox"] = 10937,
+ ["prnap"] = 10937,
+ ["scnap"] = 10938,
+ ["succnapprox"] = 10938,
+ ["Pr"] = 10939,
+ ["Sc"] = 10940,
+ ["subdot"] = 10941,
+ ["supdot"] = 10942,
+ ["subplus"] = 10943,
+ ["supplus"] = 10944,
+ ["submult"] = 10945,
+ ["supmult"] = 10946,
+ ["subedot"] = 10947,
+ ["supedot"] = 10948,
+ ["nsubE"] = {10949, 824},
+ ["nsubseteqq"] = {10949, 824},
+ ["subE"] = 10949,
+ ["subseteqq"] = 10949,
+ ["nsupE"] = {10950, 824},
+ ["nsupseteqq"] = {10950, 824},
+ ["supE"] = 10950,
+ ["supseteqq"] = 10950,
+ ["subsim"] = 10951,
+ ["supsim"] = 10952,
+ ["subnE"] = 10955,
+ ["subsetneqq"] = 10955,
+ ["varsubsetneqq"] = {10955, 65024},
+ ["vsubnE"] = {10955, 65024},
+ ["supnE"] = 10956,
+ ["supsetneqq"] = 10956,
+ ["varsupsetneqq"] = {10956, 65024},
+ ["vsupnE"] = {10956, 65024},
+ ["csub"] = 10959,
+ ["csup"] = 10960,
+ ["csube"] = 10961,
+ ["csupe"] = 10962,
+ ["subsup"] = 10963,
+ ["supsub"] = 10964,
+ ["subsub"] = 10965,
+ ["supsup"] = 10966,
+ ["suphsub"] = 10967,
+ ["supdsub"] = 10968,
+ ["forkv"] = 10969,
+ ["topfork"] = 10970,
+ ["mlcp"] = 10971,
+ ["Dashv"] = 10980,
+ ["DoubleLeftTee"] = 10980,
+ ["Vdashl"] = 10982,
+ ["Barv"] = 10983,
+ ["vBar"] = 10984,
+ ["vBarv"] = 10985,
+ ["Vbar"] = 10987,
+ ["Not"] = 10988,
+ ["bNot"] = 10989,
+ ["rnmid"] = 10990,
+ ["cirmid"] = 10991,
+ ["midcir"] = 10992,
+ ["topcir"] = 10993,
+ ["nhpar"] = 10994,
+ ["parsim"] = 10995,
+ ["nparsl"] = {11005, 8421},
+ ["parsl"] = 11005,
+ ["fflig"] = 64256,
+ ["filig"] = 64257,
+ ["fllig"] = 64258,
+ ["ffilig"] = 64259,
+ ["ffllig"] = 64260,
+ ["Ascr"] = 119964,
+ ["Cscr"] = 119966,
+ ["Dscr"] = 119967,
+ ["Gscr"] = 119970,
+ ["Jscr"] = 119973,
+ ["Kscr"] = 119974,
+ ["Nscr"] = 119977,
+ ["Oscr"] = 119978,
+ ["Pscr"] = 119979,
+ ["Qscr"] = 119980,
+ ["Sscr"] = 119982,
+ ["Tscr"] = 119983,
+ ["Uscr"] = 119984,
+ ["Vscr"] = 119985,
+ ["Wscr"] = 119986,
+ ["Xscr"] = 119987,
+ ["Yscr"] = 119988,
+ ["Zscr"] = 119989,
+ ["ascr"] = 119990,
+ ["bscr"] = 119991,
+ ["cscr"] = 119992,
+ ["dscr"] = 119993,
+ ["fscr"] = 119995,
+ ["hscr"] = 119997,
+ ["iscr"] = 119998,
+ ["jscr"] = 119999,
+ ["kscr"] = 120000,
+ ["lscr"] = 120001,
+ ["mscr"] = 120002,
+ ["nscr"] = 120003,
+ ["pscr"] = 120005,
+ ["qscr"] = 120006,
+ ["rscr"] = 120007,
+ ["sscr"] = 120008,
+ ["tscr"] = 120009,
+ ["uscr"] = 120010,
+ ["vscr"] = 120011,
+ ["wscr"] = 120012,
+ ["xscr"] = 120013,
+ ["yscr"] = 120014,
+ ["zscr"] = 120015,
+ ["Afr"] = 120068,
+ ["Bfr"] = 120069,
+ ["Dfr"] = 120071,
+ ["Efr"] = 120072,
+ ["Ffr"] = 120073,
+ ["Gfr"] = 120074,
+ ["Jfr"] = 120077,
+ ["Kfr"] = 120078,
+ ["Lfr"] = 120079,
+ ["Mfr"] = 120080,
+ ["Nfr"] = 120081,
+ ["Ofr"] = 120082,
+ ["Pfr"] = 120083,
+ ["Qfr"] = 120084,
+ ["Sfr"] = 120086,
+ ["Tfr"] = 120087,
+ ["Ufr"] = 120088,
+ ["Vfr"] = 120089,
+ ["Wfr"] = 120090,
+ ["Xfr"] = 120091,
+ ["Yfr"] = 120092,
+ ["afr"] = 120094,
+ ["bfr"] = 120095,
+ ["cfr"] = 120096,
+ ["dfr"] = 120097,
+ ["efr"] = 120098,
+ ["ffr"] = 120099,
+ ["gfr"] = 120100,
+ ["hfr"] = 120101,
+ ["ifr"] = 120102,
+ ["jfr"] = 120103,
+ ["kfr"] = 120104,
+ ["lfr"] = 120105,
+ ["mfr"] = 120106,
+ ["nfr"] = 120107,
+ ["ofr"] = 120108,
+ ["pfr"] = 120109,
+ ["qfr"] = 120110,
+ ["rfr"] = 120111,
+ ["sfr"] = 120112,
+ ["tfr"] = 120113,
+ ["ufr"] = 120114,
+ ["vfr"] = 120115,
+ ["wfr"] = 120116,
+ ["xfr"] = 120117,
+ ["yfr"] = 120118,
+ ["zfr"] = 120119,
+ ["Aopf"] = 120120,
+ ["Bopf"] = 120121,
+ ["Dopf"] = 120123,
+ ["Eopf"] = 120124,
+ ["Fopf"] = 120125,
+ ["Gopf"] = 120126,
+ ["Iopf"] = 120128,
+ ["Jopf"] = 120129,
+ ["Kopf"] = 120130,
+ ["Lopf"] = 120131,
+ ["Mopf"] = 120132,
+ ["Oopf"] = 120134,
+ ["Sopf"] = 120138,
+ ["Topf"] = 120139,
+ ["Uopf"] = 120140,
+ ["Vopf"] = 120141,
+ ["Wopf"] = 120142,
+ ["Xopf"] = 120143,
+ ["Yopf"] = 120144,
+ ["aopf"] = 120146,
+ ["bopf"] = 120147,
+ ["copf"] = 120148,
+ ["dopf"] = 120149,
+ ["eopf"] = 120150,
+ ["fopf"] = 120151,
+ ["gopf"] = 120152,
+ ["hopf"] = 120153,
+ ["iopf"] = 120154,
+ ["jopf"] = 120155,
+ ["kopf"] = 120156,
+ ["lopf"] = 120157,
+ ["mopf"] = 120158,
+ ["nopf"] = 120159,
+ ["oopf"] = 120160,
+ ["popf"] = 120161,
+ ["qopf"] = 120162,
+ ["ropf"] = 120163,
+ ["sopf"] = 120164,
+ ["topf"] = 120165,
+ ["uopf"] = 120166,
+ ["vopf"] = 120167,
+ ["wopf"] = 120168,
+ ["xopf"] = 120169,
+ ["yopf"] = 120170,
+ ["zopf"] = 120171,
+}
+function entities.dec_entity(s)
+ local n = tonumber(s)
+ if n == nil then
+ return "&#" .. s .. ";" -- fallback for unknown entities
+ end
+ return unicode.utf8.char(n)
+end
+function entities.hex_entity(s)
+ local n = tonumber("0x"..s)
+ if n == nil then
+ return "&#x" .. s .. ";" -- fallback for unknown entities
+ end
+ return unicode.utf8.char(n)
+end
+function entities.hex_entity_with_x_char(x, s)
+ local n = tonumber("0x"..s)
+ if n == nil then
+ return "&#" .. x .. s .. ";" -- fallback for unknown entities
+ end
+ return unicode.utf8.char(n)
+end
+function entities.char_entity(s)
+ local code_points = character_entities[s]
+ if code_points == nil then
+ return "&" .. s .. ";"
+ end
+ if type(code_points) ~= 'table' then
+ code_points = {code_points}
+ end
+ local char_table = {}
+ for _, code_point in ipairs(code_points) do
+ table.insert(char_table, unicode.utf8.char(code_point))
+ end
+ return table.concat(char_table)
+end
+M.writer = {}
+function M.writer.new(options)
+ local self = {}
+ self.options = options
+ self.flatten_inlines = false
+ local slice_specifiers = {}
+ for specifier in options.slice:gmatch("[^%s]+") do
+ table.insert(slice_specifiers, specifier)
+ end
+
+ if #slice_specifiers == 2 then
+ self.slice_begin, self.slice_end = table.unpack(slice_specifiers)
+ local slice_begin_type = self.slice_begin:sub(1, 1)
+ if slice_begin_type ~= "^" and slice_begin_type ~= "$" then
+ self.slice_begin = "^" .. self.slice_begin
+ end
+ local slice_end_type = self.slice_end:sub(1, 1)
+ if slice_end_type ~= "^" and slice_end_type ~= "$" then
+ self.slice_end = "$" .. self.slice_end
+ end
+ elseif #slice_specifiers == 1 then
+ self.slice_begin = "^" .. slice_specifiers[1]
+ self.slice_end = "$" .. slice_specifiers[1]
+ end
+
+ self.slice_begin_type = self.slice_begin:sub(1, 1)
+ self.slice_begin_identifier = self.slice_begin:sub(2) or ""
+ self.slice_end_type = self.slice_end:sub(1, 1)
+ self.slice_end_identifier = self.slice_end:sub(2) or ""
+
+ if self.slice_begin == "^" and self.slice_end ~= "^" then
+ self.is_writing = true
+ else
+ self.is_writing = false
+ end
+ self.space = " "
+ self.nbsp = "\\markdownRendererNbsp{}"
+ function self.plain(s)
+ return s
+ end
+ function self.paragraph(s)
+ if not self.is_writing then return "" end
+ return s
+ end
+ self.interblocksep_text = "\\markdownRendererInterblockSeparator\n{}"
+ function self.interblocksep()
+ if not self.is_writing then return "" end
+ return self.interblocksep_text
+ end
+ self.paragraphsep_text = "\\markdownRendererParagraphSeparator\n{}"
+ function self.paragraphsep()
+ if not self.is_writing then return "" end
+ return self.paragraphsep_text
+ end
+ self.undosep_text = "\\markdownRendererUndoSeparator\n{}"
+ function self.undosep()
+ if not self.is_writing then return "" end
+ return self.undosep_text
+ end
+ self.soft_line_break = function()
+ if self.flatten_inlines then return "\n" end
+ return "\\markdownRendererSoftLineBreak\n{}"
+ end
+ self.hard_line_break = function()
+ if self.flatten_inlines then return "\n" end
+ return "\\markdownRendererHardLineBreak\n{}"
+ end
+ self.ellipsis = "\\markdownRendererEllipsis{}"
+ function self.thematic_break()
+ if not self.is_writing then return "" end
+ return "\\markdownRendererThematicBreak{}"
+ end
+ self.escaped_uri_chars = {
+ ["{"] = "\\markdownRendererLeftBrace{}",
+ ["}"] = "\\markdownRendererRightBrace{}",
+ ["\\"] = "\\markdownRendererBackslash{}",
+ ["\r"] = " ",
+ ["\n"] = " ",
+ }
+ self.escaped_minimal_strings = {
+ ["^^"] = "\\markdownRendererCircumflex"
+ .. "\\markdownRendererCircumflex ",
+ ["☒"] = "\\markdownRendererTickedBox{}",
+ ["⌛"] = "\\markdownRendererHalfTickedBox{}",
+ ["☐"] = "\\markdownRendererUntickedBox{}",
+ [entities.hex_entity('FFFD')]
+ = "\\markdownRendererReplacementCharacter{}",
+ }
+ self.escaped_strings = util.table_copy(self.escaped_minimal_strings)
+ self.escaped_strings[entities.hex_entity('00A0')] = self.nbsp
+ self.escaped_chars = {
+ ["{"] = "\\markdownRendererLeftBrace{}",
+ ["}"] = "\\markdownRendererRightBrace{}",
+ ["%"] = "\\markdownRendererPercentSign{}",
+ ["\\"] = "\\markdownRendererBackslash{}",
+ ["#"] = "\\markdownRendererHash{}",
+ ["$"] = "\\markdownRendererDollarSign{}",
+ ["&"] = "\\markdownRendererAmpersand{}",
+ ["_"] = "\\markdownRendererUnderscore{}",
+ ["^"] = "\\markdownRendererCircumflex{}",
+ ["~"] = "\\markdownRendererTilde{}",
+ ["|"] = "\\markdownRendererPipe{}",
+ [entities.hex_entity('0000')]
+ = "\\markdownRendererReplacementCharacter{}",
+ }
+ local function create_escaper(char_escapes, string_escapes)
+ local escape = util.escaper(char_escapes, string_escapes)
+ return function(s)
+ if self.flatten_inlines then return s end
+ return escape(s)
+ end
+ end
+ local escape_typographic_text = create_escaper(
+ self.escaped_chars, self.escaped_strings)
+ local escape_programmatic_text = create_escaper(
+ self.escaped_uri_chars, self.escaped_minimal_strings)
+ local escape_minimal = create_escaper(
+ {}, self.escaped_minimal_strings)
+ self.escape = escape_typographic_text
+ self.math = escape_minimal
+ if options.hybrid then
+ self.identifier = escape_minimal
+ self.string = escape_minimal
+ self.uri = escape_minimal
+ self.infostring = escape_minimal
+ else
+ self.identifier = escape_programmatic_text
+ self.string = escape_typographic_text
+ self.uri = escape_programmatic_text
+ self.infostring = escape_programmatic_text
+ end
+ function self.warning(t)
+ return {"\\markdownRendererWarning{", self.identifier(t), "}"}
+ end
+ function self.error(t)
+ return {"\\markdownRendererError{", self.identifier(t), "}"}
+ end
+ function self.code(s, attributes)
+ if self.flatten_inlines then return s end
+ local buf = {}
+ if attributes ~= nil then
+ table.insert(buf,
+ "\\markdownRendererCodeSpanAttributeContextBegin\n")
+ table.insert(buf, self.attributes(attributes))
+ end
+ table.insert(buf,
+ {"\\markdownRendererCodeSpan{", self.escape(s), "}"})
+ if attributes ~= nil then
+ table.insert(buf,
+ "\\markdownRendererCodeSpanAttributeContextEnd{}")
+ end
+ return buf
+ end
+ function self.link(lab, src, tit, attributes)
+ if self.flatten_inlines then return lab end
+ local buf = {}
+ if attributes ~= nil then
+ table.insert(buf,
+ "\\markdownRendererLinkAttributeContextBegin\n")
+ table.insert(buf, self.attributes(attributes))
+ end
+ table.insert(buf, {"\\markdownRendererLink{",lab,"}",
+ "{",self.escape(src),"}",
+ "{",self.uri(src),"}",
+ "{",self.string(tit or ""),"}"})
+ if attributes ~= nil then
+ table.insert(buf,
+ "\\markdownRendererLinkAttributeContextEnd{}")
+ end
+ return buf
+ end
+ function self.image(lab, src, tit, attributes)
+ if self.flatten_inlines then return lab end
+ local buf = {}
+ if attributes ~= nil then
+ table.insert(buf,
+ "\\markdownRendererImageAttributeContextBegin\n")
+ table.insert(buf, self.attributes(attributes))
+ end
+ table.insert(buf, {"\\markdownRendererImage{",lab,"}",
+ "{",self.string(src),"}",
+ "{",self.uri(src),"}",
+ "{",self.string(tit or ""),"}"})
+ if attributes ~= nil then
+ table.insert(buf,
+ "\\markdownRendererImageAttributeContextEnd{}")
+ end
+ return buf
+ end
+ function self.bulletlist(items,tight)
+ if not self.is_writing then return "" end
+ local buffer = {}
+ for _,item in ipairs(items) do
+ if item ~= "" then
+ buffer[#buffer + 1] = self.bulletitem(item)
+ end
+ end
+ local contents = util.intersperse(buffer,"\n")
+ if tight and options.tightLists then
+ return {"\\markdownRendererUlBeginTight\n",contents,
+ "\n\\markdownRendererUlEndTight "}
+ else
+ return {"\\markdownRendererUlBegin\n",contents,
+ "\n\\markdownRendererUlEnd "}
+ end
+ end
+ function self.bulletitem(s)
+ return {"\\markdownRendererUlItem ",s,
+ "\\markdownRendererUlItemEnd "}
+ end
+ function self.orderedlist(items,tight,startnum)
+ if not self.is_writing then return "" end
+ local buffer = {}
+ local num = startnum
+ for _,item in ipairs(items) do
+ if item ~= "" then
+ buffer[#buffer + 1] = self.ordereditem(item,num)
+ end
+ if num ~= nil and item ~= "" then
+ num = num + 1
+ end
+ end
+ local contents = util.intersperse(buffer,"\n")
+ if tight and options.tightLists then
+ return {"\\markdownRendererOlBeginTight\n",contents,
+ "\n\\markdownRendererOlEndTight "}
+ else
+ return {"\\markdownRendererOlBegin\n",contents,
+ "\n\\markdownRendererOlEnd "}
+ end
+ end
+ function self.ordereditem(s,num)
+ if num ~= nil then
+ return {"\\markdownRendererOlItemWithNumber{",num,"}",s,
+ "\\markdownRendererOlItemEnd "}
+ else
+ return {"\\markdownRendererOlItem ",s,
+ "\\markdownRendererOlItemEnd "}
+ end
+ end
+ function self.inline_html_comment(contents)
+ if self.flatten_inlines then return contents end
+ return {"\\markdownRendererInlineHtmlComment{",contents,"}"}
+ end
+ function self.inline_html_tag(contents)
+ if self.flatten_inlines then return contents end
+ return {"\\markdownRendererInlineHtmlTag{",
+ self.string(contents),"}"}
+ end
+ function self.block_html_element(s)
+ if not self.is_writing then return "" end
+ local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim")
+ return {"\\markdownRendererInputBlockHtmlElement{",name,"}"}
+ end
+ function self.emphasis(s)
+ if self.flatten_inlines then return s end
+ return {"\\markdownRendererEmphasis{",s,"}"}
+ end
+ function self.tickbox(f)
+ if f == 1.0 then
+ return "☒ "
+ elseif f == 0.0 then
+ return "☐ "
+ else
+ return "⌛ "
+ end
+ end
+ function self.strong(s)
+ if self.flatten_inlines then return s end
+ return {"\\markdownRendererStrongEmphasis{",s,"}"}
+ end
+ function self.blockquote(s)
+ if not self.is_writing then return "" end
+ return {"\\markdownRendererBlockQuoteBegin\n",s,
+ "\\markdownRendererBlockQuoteEnd "}
+ end
+ function self.verbatim(s)
+ if not self.is_writing then return "" end
+ s = s:gsub("\n$", "")
+ local name = util.cache_verbatim(options.cacheDir, s)
+ return {"\\markdownRendererInputVerbatim{",name,"}"}
+ end
+ function self.document(d)
+ local buf = {"\\markdownRendererDocumentBegin\n", d}
+
+ -- pop all attributes
+ table.insert(buf, self.pop_attributes())
+
+ table.insert(buf, "\\markdownRendererDocumentEnd")
+
+ return buf
+ end
+ local seen_identifiers = {}
+ local key_value_regex = "([^= ]+)%s*=%s*(.*)"
+ local function normalize_attributes(attributes, auto_identifiers)
+ -- normalize attributes
+ local normalized_attributes = {}
+ local has_explicit_identifiers = false
+ local key, value
+ for _, attribute in ipairs(attributes or {}) do
+ if attribute:sub(1, 1) == "#" then
+ table.insert(normalized_attributes, attribute)
+ has_explicit_identifiers = true
+ seen_identifiers[attribute:sub(2)] = true
+ elseif attribute:sub(1, 1) == "." then
+ table.insert(normalized_attributes, attribute)
+ else
+ key, value = attribute:match(key_value_regex)
+ if key:lower() == "id" then
+ table.insert(normalized_attributes, "#" .. value)
+ elseif key:lower() == "class" then
+ local classes = {}
+ for class in value:gmatch("%S+") do
+ table.insert(classes, class)
+ end
+ table.sort(classes)
+ for _, class in ipairs(classes) do
+ table.insert(normalized_attributes, "." .. class)
+ end
+ else
+ table.insert(normalized_attributes, attribute)
+ end
+ end
+ end
+
+ -- if no explicit identifiers exist, add auto identifiers
+ if not has_explicit_identifiers and auto_identifiers ~= nil then
+ local seen_auto_identifiers = {}
+ for _, auto_identifier in ipairs(auto_identifiers) do
+ if seen_auto_identifiers[auto_identifier] == nil then
+ seen_auto_identifiers[auto_identifier] = true
+ if seen_identifiers[auto_identifier] == nil then
+ seen_identifiers[auto_identifier] = true
+ table.insert(normalized_attributes,
+ "#" .. auto_identifier)
+ else
+ local auto_identifier_number = 1
+ while true do
+ local numbered_auto_identifier = auto_identifier .. "-"
+ .. auto_identifier_number
+ if seen_identifiers[numbered_auto_identifier] == nil then
+ seen_identifiers[numbered_auto_identifier] = true
+ table.insert(normalized_attributes,
+ "#" .. numbered_auto_identifier)
+ break
+ end
+ auto_identifier_number = auto_identifier_number + 1
+ end
+ end
+ end
+ end
+ end
+
+ -- sort and deduplicate normalized attributes
+ table.sort(normalized_attributes)
+ local seen_normalized_attributes = {}
+ local deduplicated_normalized_attributes = {}
+ for _, attribute in ipairs(normalized_attributes) do
+ if seen_normalized_attributes[attribute] == nil then
+ seen_normalized_attributes[attribute] = true
+ table.insert(deduplicated_normalized_attributes, attribute)
+ end
+ end
+
+ return deduplicated_normalized_attributes
+ end
+
+ function self.attributes(attributes, should_normalize_attributes)
+ local normalized_attributes
+ if should_normalize_attributes == false then
+ normalized_attributes = attributes
+ else
+ normalized_attributes = normalize_attributes(attributes)
+ end
+
+ local buf = {}
+ local key, value
+ for _, attribute in ipairs(normalized_attributes) do
+ if attribute:sub(1, 1) == "#" then
+ table.insert(buf, {"\\markdownRendererAttributeIdentifier{",
+ attribute:sub(2), "}"})
+ elseif attribute:sub(1, 1) == "." then
+ table.insert(buf, {"\\markdownRendererAttributeClassName{",
+ attribute:sub(2), "}"})
+ else
+ key, value = attribute:match(key_value_regex)
+ table.insert(buf, {"\\markdownRendererAttributeKeyValue{",
+ key, "}{", value, "}"})
+ end
+ end
+
+ return buf
+ end
+ self.active_attributes = {}
+ self.attribute_type_levels = {}
+ setmetatable(self.attribute_type_levels,
+ { __index = function() return 0 end })
+ local function apply_attributes()
+ local buf = {}
+ for i = 1, #self.active_attributes do
+ local start_output = self.active_attributes[i][3]
+ if start_output ~= nil then
+ table.insert(buf, start_output)
+ end
+ end
+ return buf
+ end
+
+ local function tear_down_attributes()
+ local buf = {}
+ for i = #self.active_attributes, 1, -1 do
+ local end_output = self.active_attributes[i][4]
+ if end_output ~= nil then
+ table.insert(buf, end_output)
+ end
+ end
+ return buf
+ end
+ function self.push_attributes(attribute_type, attributes,
+ start_output, end_output)
+ local attribute_type_level
+ = self.attribute_type_levels[attribute_type]
+ self.attribute_type_levels[attribute_type]
+ = attribute_type_level + 1
+
+ -- index attributes in a hash table for easy lookup
+ attributes = attributes or {}
+ for i = 1, #attributes do
+ attributes[attributes[i]] = true
+ end
+
+ local buf = {}
+ -- handle slicing
+ if attributes["#" .. self.slice_end_identifier] ~= nil and
+ self.slice_end_type == "^" then
+ if self.is_writing then
+ table.insert(buf, self.undosep())
+ table.insert(buf, tear_down_attributes())
+ end
+ self.is_writing = false
+ end
+ if attributes["#" .. self.slice_begin_identifier] ~= nil and
+ self.slice_begin_type == "^" then
+ table.insert(buf, apply_attributes())
+ self.is_writing = true
+ end
+ if self.is_writing and start_output ~= nil then
+ table.insert(buf, start_output)
+ end
+ table.insert(self.active_attributes,
+ {attribute_type, attributes,
+ start_output, end_output})
+ return buf
+ end
+
+ function self.pop_attributes(attribute_type)
+ local buf = {}
+ -- pop attributes until we find attributes of correct type
+ -- or until no attributes remain
+ local current_attribute_type = false
+ while current_attribute_type ~= attribute_type and
+ #self.active_attributes > 0 do
+ local attributes, _, end_output
+ current_attribute_type, attributes, _, end_output = table.unpack(
+ self.active_attributes[#self.active_attributes])
+ local attribute_type_level
+ = self.attribute_type_levels[current_attribute_type]
+ self.attribute_type_levels[current_attribute_type]
+ = attribute_type_level - 1
+ if self.is_writing and end_output ~= nil then
+ table.insert(buf, end_output)
+ end
+ table.remove(self.active_attributes, #self.active_attributes)
+ -- handle slicing
+ if attributes["#" .. self.slice_end_identifier] ~= nil
+ and self.slice_end_type == "$" then
+ if self.is_writing then
+ table.insert(buf, self.undosep())
+ table.insert(buf, tear_down_attributes())
+ end
+ self.is_writing = false
+ end
+ if attributes["#" .. self.slice_begin_identifier] ~= nil and
+ self.slice_begin_type == "$" then
+ self.is_writing = true
+ table.insert(buf, apply_attributes())
+ end
+ end
+ return buf
+ end
+ local function create_auto_identifier(s)
+ local buffer = {}
+ local prev_space = false
+ local letter_found = false
+ local normalized_s = s
+ if not options.unicodeNormalization
+ or options.unicodeNormalizationForm ~= "nfc" then
+ normalized_s = uni_algos.normalize.NFC(normalized_s)
+ end
+
+ for _, code in utf8.codes(normalized_s) do
+ local char = utf8.char(code)
+
+ -- Remove everything up to the first letter.
+ if not letter_found then
+ local is_letter = unicode.utf8.match(char, "%a")
+ if is_letter then
+ letter_found = true
+ else
+ goto continue
+ end
+ end
+
+ -- Remove all non-alphanumeric characters, except underscores,
+ -- hyphens, and periods.
+ if not unicode.utf8.match(char, "[%w_%-%.%s]") then
+ goto continue
+ end
+
+ -- Replace all spaces and newlines with hyphens.
+ if unicode.utf8.match(char, "[%s\n]") then
+ char = "-"
+ if prev_space then
+ goto continue
+ else
+ prev_space = true
+ end
+ else
+ -- Convert all alphabetic characters to lowercase.
+ char = unicode.utf8.lower(char)
+ prev_space = false
+ end
+
+ table.insert(buffer, char)
+
+ ::continue::
+ end
+
+ if prev_space then
+ table.remove(buffer)
+ end
+
+ local identifier = #buffer == 0 and "section"
+ or table.concat(buffer, "")
+ return identifier
+ end
+ local function create_gfm_auto_identifier(s)
+ local buffer = {}
+ local prev_space = false
+ local letter_found = false
+ local normalized_s = s
+ if not options.unicodeNormalization
+ or options.unicodeNormalizationForm ~= "nfc" then
+ normalized_s = uni_algos.normalize.NFC(normalized_s)
+ end
+
+ for _, code in utf8.codes(normalized_s) do
+ local char = utf8.char(code)
+
+ -- Remove everything up to the first non-space.
+ if not letter_found then
+ local is_letter = unicode.utf8.match(char, "%S")
+ if is_letter then
+ letter_found = true
+ else
+ goto continue
+ end
+ end
+
+ -- Remove all non-alphanumeric characters, except underscores
+ -- and hyphens.
+ if not unicode.utf8.match(char, "[%w_%-%s]") then
+ prev_space = false
+ goto continue
+ end
+
+ -- Replace all spaces and newlines with hyphens.
+ if unicode.utf8.match(char, "[%s\n]") then
+ char = "-"
+ if prev_space then
+ goto continue
+ else
+ prev_space = true
+ end
+ else
+ -- Convert all alphabetic characters to lowercase.
+ char = unicode.utf8.lower(char)
+ prev_space = false
+ end
+
+ table.insert(buffer, char)
+
+ ::continue::
+ end
+
+ if prev_space then
+ table.remove(buffer)
+ end
+
+ local identifier = #buffer == 0 and "section"
+ or table.concat(buffer, "")
+ return identifier
+ end
+ self.secbegin_text = "\\markdownRendererSectionBegin\n"
+ self.secend_text = "\n\\markdownRendererSectionEnd "
+ function self.heading(s, level, attributes)
+ local buf = {}
+ local flat_text, inlines = table.unpack(s)
+
+ -- push empty attributes for implied sections
+ while self.attribute_type_levels["heading"] < level - 1 do
+ table.insert(buf,
+ self.push_attributes("heading",
+ nil,
+ self.secbegin_text,
+ self.secend_text))
+ end
+
+ -- pop attributes for sections that have ended
+ while self.attribute_type_levels["heading"] >= level do
+ table.insert(buf, self.pop_attributes("heading"))
+ end
+
+ -- construct attributes for the new section
+ local auto_identifiers = {}
+ if self.options.autoIdentifiers then
+ table.insert(auto_identifiers, create_auto_identifier(flat_text))
+ end
+ if self.options.gfmAutoIdentifiers then
+ table.insert(auto_identifiers,
+ create_gfm_auto_identifier(flat_text))
+ end
+ local normalized_attributes = normalize_attributes(attributes,
+ auto_identifiers)
+
+ -- push attributes for the new section
+ local start_output = {}
+ local end_output = {}
+ table.insert(start_output, self.secbegin_text)
+ table.insert(end_output, self.secend_text)
+
+ table.insert(buf, self.push_attributes("heading",
+ normalized_attributes,
+ start_output,
+ end_output))
+ assert(self.attribute_type_levels["heading"] == level)
+
+ -- render the heading and its attributes
+ if self.is_writing and #normalized_attributes > 0 then
+ table.insert(buf,
+ "\\markdownRendererHeaderAttributeContextBegin\n")
+ table.insert(buf, self.attributes(normalized_attributes, false))
+ end
+
+ local cmd
+ level = level + options.shiftHeadings
+ if level <= 1 then
+ cmd = "\\markdownRendererHeadingOne"
+ elseif level == 2 then
+ cmd = "\\markdownRendererHeadingTwo"
+ elseif level == 3 then
+ cmd = "\\markdownRendererHeadingThree"
+ elseif level == 4 then
+ cmd = "\\markdownRendererHeadingFour"
+ elseif level == 5 then
+ cmd = "\\markdownRendererHeadingFive"
+ elseif level >= 6 then
+ cmd = "\\markdownRendererHeadingSix"
+ else
+ cmd = ""
+ end
+ if self.is_writing then
+ table.insert(buf, {cmd, "{", inlines, "}"})
+ end
+
+ if self.is_writing and #normalized_attributes > 0 then
+ table.insert(buf, "\\markdownRendererHeaderAttributeContextEnd{}")
+ end
+
+ return buf
+ end
+ function self.get_state()
+ return {
+ is_writing=self.is_writing,
+ flatten_inlines=self.flatten_inlines,
+ active_attributes={table.unpack(self.active_attributes)},
+ }
+ end
+ function self.set_state(s)
+ local previous_state = self.get_state()
+ for key, value in pairs(s) do
+ self[key] = value
+ end
+ return previous_state
+ end
+ function self.defer_call(f)
+ local previous_state = self.get_state()
+ return function(...)
+ local state = self.set_state(previous_state)
+ local return_value = f(...)
+ self.set_state(state)
+ return return_value
+ end
+ end
+
+ return self
+end
+local parsers = {}
+parsers.percent = P("%")
+parsers.at = P("@")
+parsers.comma = P(",")
+parsers.asterisk = P("*")
+parsers.dash = P("-")
+parsers.plus = P("+")
+parsers.underscore = P("_")
+parsers.period = P(".")
+parsers.hash = P("#")
+parsers.dollar = P("$")
+parsers.ampersand = P("&")
+parsers.backtick = P("`")
+parsers.less = P("<")
+parsers.more = P(">")
+parsers.space = P(" ")
+parsers.squote = P("'")
+parsers.dquote = P('"')
+parsers.lparent = P("(")
+parsers.rparent = P(")")
+parsers.lbracket = P("[")
+parsers.rbracket = P("]")
+parsers.lbrace = P("{")
+parsers.rbrace = P("}")
+parsers.circumflex = P("^")
+parsers.slash = P("/")
+parsers.equal = P("=")
+parsers.colon = P(":")
+parsers.semicolon = P(";")
+parsers.exclamation = P("!")
+parsers.pipe = P("|")
+parsers.tilde = P("~")
+parsers.backslash = P("\\")
+parsers.tab = P("\t")
+parsers.newline = P("\n")
+
+parsers.digit = R("09")
+parsers.hexdigit = R("09","af","AF")
+parsers.letter = R("AZ","az")
+parsers.alphanumeric = R("AZ","az","09")
+parsers.keyword = parsers.letter
+ * (parsers.alphanumeric + parsers.dash)^0
+
+parsers.doubleasterisks = P("**")
+parsers.doubleunderscores = P("__")
+parsers.doubletildes = P("~~")
+parsers.fourspaces = P(" ")
+
+parsers.any = P(1)
+parsers.succeed = P(true)
+parsers.fail = P(false)
+
+parsers.internal_punctuation = S(":;,.?")
+parsers.ascii_punctuation = S("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~")
+;(function()
+ local pathname = assert(kpse.find_file("UnicodeData.txt"),
+ [[Could not locate file "UnicodeData.txt"]])
+ local file = assert(io.open(pathname, "r"),
+ [[Could not open file "UnicodeData.txt"]])
+ local prefix_trees = {}
+ for line in file:lines() do
+ local codepoint, major_category = line:match("^(%x+);[^;]*;(%a)")
+ if major_category == "P" or major_category == "S" then
+ local code = unicode.utf8.char(tonumber(codepoint, 16))
+ if prefix_trees[#code] == nil then
+ prefix_trees[#code] = {}
+ end
+ local node = prefix_trees[#code]
+ for i = 1, #code do
+ local byte = code:sub(i, i)
+ if i < #code then
+ if node[byte] == nil then
+ node[byte] = {}
+ end
+ node = node[byte]
+ else
+ table.insert(node, byte)
+ end
+ end
+ end
+ end
+ assert(file:close())
+ local function depth_first_search(node, path, visit, leave)
+ visit(node, path)
+ for label, child in pairs(node) do
+ if type(child) == "table" then
+ depth_first_search(child, path .. label, visit, leave)
+ else
+ visit(child, path)
+ end
+ end
+ leave(node, path)
+ end
+
+ parsers.punctuation = {}
+ for length, prefix_tree in pairs(prefix_trees) do
+ local subparsers = {}
+ depth_first_search(prefix_tree, "", function(node, path)
+ if type(node) == "table" then
+ subparsers[path] = parsers.fail
+ else
+ assert(type(node) == "string")
+ subparsers[path] = subparsers[path] + S(node)
+ end
+ end, function(_, path)
+ if #path > 0 then
+ local byte = path:sub(#path, #path)
+ local parent_path = path:sub(1, #path-1)
+ subparsers[parent_path] = subparsers[parent_path]
+ + S(byte) * subparsers[path]
+ else
+ parsers.punctuation[length] = subparsers[path]
+ end
+ end)
+ assert(parsers.punctuation[length] ~= nil)
+ end
+end)()
+
+parsers.escapable = parsers.ascii_punctuation
+parsers.anyescaped = parsers.backslash / ""
+ * parsers.escapable
+ + parsers.any
+
+parsers.spacechar = S("\t ")
+parsers.spacing = S(" \n\r\t")
+parsers.nonspacechar = parsers.any - parsers.spacing
+parsers.optionalspace = parsers.spacechar^0
+
+parsers.normalchar = parsers.any - (V("SpecialChar")
+ + parsers.spacing)
+parsers.eof = -parsers.any
+parsers.nonindentspace = parsers.space^-3 * - parsers.spacechar
+parsers.indent = parsers.space^-3 * parsers.tab
+ + parsers.fourspaces / ""
+parsers.linechar = P(1 - parsers.newline)
+
+parsers.blankline = parsers.optionalspace
+ * parsers.newline / "\n"
+parsers.blanklines = parsers.blankline^0
+parsers.skipblanklines = ( parsers.optionalspace
+ * parsers.newline)^0
+parsers.indentedline = parsers.indent /""
+ * C( parsers.linechar^1
+ * parsers.newline^-1)
+parsers.optionallyindentedline = parsers.indent^-1 /""
+ * C( parsers.linechar^1
+ * parsers.newline^-1)
+parsers.sp = parsers.spacing^0
+parsers.spnl = parsers.optionalspace
+ * ( parsers.newline
+ * parsers.optionalspace)^-1
+parsers.line = parsers.linechar^0 * parsers.newline
+parsers.nonemptyline = parsers.line - parsers.blankline
+
+parsers.leader = parsers.space^-3
+
+local function has_trail(indent_table)
+ return indent_table ~= nil and
+ indent_table.trail ~= nil and
+ next(indent_table.trail) ~= nil
+end
+
+local function has_indents(indent_table)
+ return indent_table ~= nil and
+ indent_table.indents ~= nil and
+ next(indent_table.indents) ~= nil
+end
+
+local function add_trail(indent_table, trail_info)
+ indent_table.trail = trail_info
+ return indent_table
+end
+
+local function remove_trail(indent_table)
+ indent_table.trail = nil
+ return indent_table
+end
+
+local function update_indent_table(indent_table, new_indent, add)
+ indent_table = remove_trail(indent_table)
+
+ if not has_indents(indent_table) then
+ indent_table.indents = {}
+ end
+
+ if add then
+ indent_table.indents[#indent_table.indents + 1] = new_indent
+ else
+ if indent_table.indents[#indent_table.indents].name
+ == new_indent.name then
+ indent_table.indents[#indent_table.indents] = nil
+ end
+ end
+
+ return indent_table
+end
+
+local function remove_indent(name)
+ local remove_indent_level =
+ function(s, i, indent_table) -- luacheck: ignore s i
+ indent_table = update_indent_table(indent_table, {name=name},
+ false)
+ return true, indent_table
+ end
+
+ return Cg(Cmt(Cb("indent_info"), remove_indent_level), "indent_info")
+end
+
+local function process_starter_spacing(indent, spacing,
+ minimum, left_strip_length)
+ left_strip_length = left_strip_length or 0
+
+ local count = 0
+ local tab_value = 4 - (indent) % 4
+
+ local code_started, minimum_found = false, false
+ local code_start, minimum_remainder = "", ""
+
+ local left_total_stripped = 0
+ local full_remainder = ""
+
+ if spacing ~= nil then
+ for i = 1, #spacing do
+ local character = spacing:sub(i, i)
+
+ if character == "\t" then
+ count = count + tab_value
+ tab_value = 4
+ elseif character == " " then
+ count = count + 1
+ tab_value = 4 - (1 - tab_value) % 4
+ end
+
+ if (left_strip_length ~= 0) then
+ local possible_to_strip = math.min(count, left_strip_length)
+ count = count - possible_to_strip
+ left_strip_length = left_strip_length - possible_to_strip
+ left_total_stripped = left_total_stripped + possible_to_strip
+ else
+ full_remainder = full_remainder .. character
+ end
+
+ if (minimum_found) then
+ minimum_remainder = minimum_remainder .. character
+ elseif (count >= minimum) then
+ minimum_found = true
+ minimum_remainder = minimum_remainder
+ .. string.rep(" ", count - minimum)
+ end
+
+ if (code_started) then
+ code_start = code_start .. character
+ elseif (count >= minimum + 4) then
+ code_started = true
+ code_start = code_start
+ .. string.rep(" ", count - (minimum + 4))
+ end
+ end
+ end
+
+ local remainder
+ if (code_started) then
+ remainder = code_start
+ else
+ remainder = string.rep(" ", count - minimum)
+ end
+
+ local is_minimum = count >= minimum
+ return {
+ is_code = code_started,
+ remainder = remainder,
+ left_total_stripped = left_total_stripped,
+ is_minimum = is_minimum,
+ minimum_remainder = minimum_remainder,
+ total_length = count,
+ full_remainder = full_remainder
+ }
+end
+
+local function count_indent_tab_level(indent_table)
+ local count = 0
+ if not has_indents(indent_table) then
+ return count
+ end
+
+ for i=1, #indent_table.indents do
+ count = count + indent_table.indents[i].length
+ end
+ return count
+end
+
+local function total_delimiter_length(delimiter)
+ local count = 0
+ if type(delimiter) == "string" then return #delimiter end
+ for _, value in pairs(delimiter) do
+ count = count + total_delimiter_length(value)
+ end
+ return count
+end
+
+local function process_starter_indent(_, _, indent_table, starter,
+ is_blank, indent_type, breakable)
+ local last_trail = starter[1]
+ local delimiter = starter[2]
+ local raw_new_trail = starter[3]
+
+ if indent_type == "bq" and not breakable then
+ indent_table.ignore_blockquote_blank = true
+ end
+
+ if has_trail(indent_table) then
+ local trail = indent_table.trail
+ if trail.is_code then
+ return false
+ end
+ last_trail = trail.remainder
+ else
+ local sp = process_starter_spacing(0, last_trail, 0, 0)
+
+ if sp.is_code then
+ return false
+ end
+ last_trail = sp.remainder
+ end
+
+ local preceding_indentation = count_indent_tab_level(indent_table) % 4
+ local last_trail_length = #last_trail
+ local delimiter_length = total_delimiter_length(delimiter)
+
+ local total_indent_level = preceding_indentation + last_trail_length
+ + delimiter_length
+
+ local sp = {}
+ if not is_blank then
+ sp = process_starter_spacing(total_indent_level, raw_new_trail,
+ 0, 1)
+ end
+
+ local del_trail_length = sp.left_total_stripped
+ if is_blank then
+ del_trail_length = 1
+ elseif not sp.is_code then
+ del_trail_length = del_trail_length + #sp.remainder
+ end
+
+ local indent_length = last_trail_length + delimiter_length
+ + del_trail_length
+ local new_indent_info = {name=indent_type, length=indent_length}
+
+ indent_table = update_indent_table(indent_table, new_indent_info,
+ true)
+ indent_table = add_trail(indent_table,
+ {is_code=sp.is_code,
+ remainder=sp.remainder,
+ total_length=sp.total_length,
+ full_remainder=sp.full_remainder})
+
+ return true, indent_table
+end
+
+local function decode_pattern(name)
+ local delimeter = parsers.succeed
+ if name == "bq" then
+ delimeter = parsers.more
+ end
+
+ return C(parsers.optionalspace) * C(delimeter)
+ * C(parsers.optionalspace) * Cp()
+end
+
+local function left_blank_starter(indent_table)
+ local blank_starter_index
+
+ if not has_indents(indent_table) then
+ return
+ end
+
+ for i = #indent_table.indents,1,-1 do
+ local value = indent_table.indents[i]
+ if value.name == "li" then
+ blank_starter_index = i
+ else
+ break
+ end
+ end
+
+ return blank_starter_index
+end
+
+local function traverse_indent(s, i, indent_table, is_optional,
+ is_blank, current_line_indents)
+ local new_index = i
+
+ local preceding_indentation = 0
+ local current_trail = {}
+
+ local blank_starter = left_blank_starter(indent_table)
+
+ if current_line_indents == nil then
+ current_line_indents = {}
+ end
+
+ for index = 1,#indent_table.indents do
+ local value = indent_table.indents[index]
+ local pattern = decode_pattern(value.name)
+
+ -- match decoded pattern
+ local new_indent_info = lpeg.match(Ct(pattern), s, new_index)
+ if new_indent_info == nil then
+ local blankline_end = lpeg.match(
+ Ct(parsers.blankline * Cg(Cp(), "pos")), s, new_index)
+ if is_optional or not indent_table.ignore_blockquote_blank
+ or not blankline_end then
+ return is_optional, new_index, current_trail,
+ current_line_indents
+ end
+
+ return traverse_indent(s, tonumber(blankline_end.pos),
+ indent_table, is_optional, is_blank,
+ current_line_indents)
+ end
+
+ local raw_last_trail = new_indent_info[1]
+ local delimiter = new_indent_info[2]
+ local raw_new_trail = new_indent_info[3]
+ local next_index = new_indent_info[4]
+
+ local space_only = delimiter == ""
+
+ -- check previous trail
+ if not space_only and next(current_trail) == nil then
+ local sp = process_starter_spacing(0, raw_last_trail, 0, 0)
+ current_trail = {is_code=sp.is_code, remainder=sp.remainder,
+ total_length=sp.total_length,
+ full_remainder=sp.full_remainder}
+ end
+
+ if next(current_trail) ~= nil then
+ if not space_only and current_trail.is_code then
+ return is_optional, new_index, current_trail,
+ current_line_indents
+ end
+ if current_trail.internal_remainder ~= nil then
+ raw_last_trail = current_trail.internal_remainder
+ end
+ end
+
+ local raw_last_trail_length = 0
+ local delimiter_length = 0
+
+ if not space_only then
+ delimiter_length = #delimiter
+ raw_last_trail_length = #raw_last_trail
+ end
+
+ local total_indent_level = preceding_indentation
+ + raw_last_trail_length + delimiter_length
+
+ local spacing_to_process
+ local minimum = 0
+ local left_strip_length = 0
+
+ if not space_only then
+ spacing_to_process = raw_new_trail
+ left_strip_length = 1
+ else
+ spacing_to_process = raw_last_trail
+ minimum = value.length
+ end
+
+ local sp = process_starter_spacing(total_indent_level,
+ spacing_to_process, minimum,
+ left_strip_length)
+
+ if space_only and not sp.is_minimum then
+ return is_optional or (is_blank and blank_starter <= index),
+ new_index, current_trail, current_line_indents
+ end
+
+ local indent_length = raw_last_trail_length + delimiter_length
+ + sp.left_total_stripped
+
+ -- update info for the next pattern
+ if not space_only then
+ preceding_indentation = preceding_indentation + indent_length
+ else
+ preceding_indentation = preceding_indentation + value.length
+ end
+
+ current_trail = {is_code=sp.is_code, remainder=sp.remainder,
+ internal_remainder=sp.minimum_remainder,
+ total_length=sp.total_length,
+ full_remainder=sp.full_remainder}
+
+ current_line_indents[#current_line_indents + 1] = new_indent_info
+ new_index = next_index
+ end
+
+ return true, new_index, current_trail, current_line_indents
+end
+
+local function check_trail(expect_code, is_code)
+ return (expect_code and is_code) or (not expect_code and not is_code)
+end
+
+local check_trail_joined =
+ function(s, i, indent_table, -- luacheck: ignore s i
+ spacing, expect_code, omit_remainder)
+ local is_code
+ local remainder
+
+ if has_trail(indent_table) then
+ local trail = indent_table.trail
+ is_code = trail.is_code
+ if is_code then
+ remainder = trail.remainder
+ else
+ remainder = trail.full_remainder
+ end
+ else
+ local sp = process_starter_spacing(0, spacing, 0, 0)
+ is_code = sp.is_code
+ if is_code then
+ remainder = sp.remainder
+ else
+ remainder = sp.full_remainder
+ end
+ end
+
+ local result = check_trail(expect_code, is_code)
+ if omit_remainder then
+ return result
+ end
+ return result, remainder
+ end
+
+local check_trail_length =
+ function(s, i, indent_table, -- luacheck: ignore s i
+ spacing, min, max)
+ local trail
+
+ if has_trail(indent_table) then
+ trail = indent_table.trail
+ else
+ trail = process_starter_spacing(0, spacing, 0, 0)
+ end
+
+ local total_length = trail.total_length
+ if total_length == nil then
+ return false
+ end
+
+ return min <= total_length and total_length <= max
+ end
+
+local function check_continuation_indentation(s, i, indent_table,
+ is_optional, is_blank)
+ if not has_indents(indent_table) then
+ return true
+ end
+
+ local passes, new_index, current_trail, current_line_indents =
+ traverse_indent(s, i, indent_table, is_optional, is_blank)
+
+ if passes then
+ indent_table.current_line_indents = current_line_indents
+ indent_table = add_trail(indent_table, current_trail)
+ return new_index, indent_table
+ end
+ return false
+end
+
+local function get_last_indent_name(indent_table)
+ if has_indents(indent_table) then
+ return indent_table.indents[#indent_table.indents].name
+ end
+end
+
+local function remove_remainder_if_blank(indent_table, remainder)
+ if get_last_indent_name(indent_table) == "li" then
+ return ""
+ end
+ return remainder
+end
+
+local check_trail_type =
+ function(s, i, -- luacheck: ignore s i
+ trail, spacing, trail_type)
+ if trail == nil then
+ trail = process_starter_spacing(0, spacing, 0, 0)
+ end
+
+ if trail_type == "non-code" then
+ return check_trail(false, trail.is_code)
+ end
+ if trail_type == "code" then
+ return check_trail(true, trail.is_code)
+ end
+ if trail_type == "full-code" then
+ if (trail.is_code) then
+ return i, trail.remainder
+ end
+ return i, ""
+ end
+ if trail_type == "full-any" then
+ return i, trail.internal_remainder
+ end
+ end
+
+local trail_freezing =
+ function(s, i, -- luacheck: ignore s i
+ indent_table, is_freezing)
+ if is_freezing then
+ if indent_table.is_trail_frozen then
+ indent_table.trail = indent_table.frozen_trail
+ else
+ indent_table.frozen_trail = indent_table.trail
+ indent_table.is_trail_frozen = true
+ end
+ else
+ indent_table.frozen_trail = nil
+ indent_table.is_trail_frozen = false
+ end
+ return true, indent_table
+ end
+
+local check_continuation_indentation_and_trail =
+ function (s, i, indent_table, is_optional, is_blank, trail_type,
+ reset_rem, omit_remainder)
+ if not has_indents(indent_table) then
+ local spacing, new_index = lpeg.match( C(parsers.spacechar^0)
+ * Cp(), s, i)
+ local result, remainder = check_trail_type(s, i,
+ indent_table.trail, spacing, trail_type)
+ if remainder == nil then
+ if result then
+ return new_index
+ end
+ return false
+ end
+ if result then
+ return new_index, remainder
+ end
+ return false
+ end
+
+ local passes, new_index, current_trail = traverse_indent(s, i,
+ indent_table, is_optional, is_blank)
+
+ if passes then
+ local spacing
+ if current_trail == nil then
+ local newer_spacing, newer_index = lpeg.match(
+ C(parsers.spacechar^0) * Cp(), s, i)
+ current_trail = process_starter_spacing(0, newer_spacing, 0, 0)
+ new_index = newer_index
+ spacing = newer_spacing
+ else
+ spacing = current_trail.remainder
+ end
+ local result, remainder = check_trail_type(s, new_index,
+ current_trail, spacing, trail_type)
+ if remainder == nil or omit_remainder then
+ if result then
+ return new_index
+ end
+ return false
+ end
+
+ if is_blank and reset_rem then
+ remainder = remove_remainder_if_blank(indent_table, remainder)
+ end
+ if result then
+ return new_index, remainder
+ end
+ return false
+ end
+ return false
+ end
+
+parsers.check_trail = Cmt( Cb("indent_info") * C(parsers.spacechar^0)
+ * Cc(false), check_trail_joined)
+
+parsers.check_trail_no_rem = Cmt( Cb("indent_info")
+ * C(parsers.spacechar^0) * Cc(false)
+ * Cc(true), check_trail_joined)
+
+parsers.check_code_trail = Cmt( Cb("indent_info")
+ * C(parsers.spacechar^0)
+ * Cc(true), check_trail_joined)
+
+parsers.check_trail_length_range = function(min, max)
+ return Cmt( Cb("indent_info") * C(parsers.spacechar^0) * Cc(min)
+ * Cc(max), check_trail_length)
+end
+
+parsers.check_trail_length = function(n)
+ return parsers.check_trail_length_range(n, n)
+end
+
+parsers.freeze_trail = Cg( Cmt(Cb("indent_info")
+ * Cc(true), trail_freezing), "indent_info")
+
+parsers.unfreeze_trail = Cg(Cmt(Cb("indent_info") * Cc(false),
+ trail_freezing), "indent_info")
+
+parsers.check_minimal_indent = Cmt(Cb("indent_info") * Cc(false),
+ check_continuation_indentation)
+
+parsers.check_optional_indent = Cmt(Cb("indent_info") * Cc(true),
+ check_continuation_indentation)
+
+parsers.check_minimal_blank_indent
+ = Cmt( Cb("indent_info") * Cc(false)
+ * Cc(true)
+ , check_continuation_indentation)
+
+
+parsers.check_minimal_indent_and_trail =
+ Cmt( Cb("indent_info")
+ * Cc(false) * Cc(false) * Cc("non-code") * Cc(true)
+ , check_continuation_indentation_and_trail)
+
+parsers.check_minimal_indent_and_code_trail =
+ Cmt( Cb("indent_info")
+ * Cc(false) * Cc(false) * Cc("code") * Cc(false)
+ , check_continuation_indentation_and_trail)
+
+parsers.check_minimal_blank_indent_and_full_code_trail =
+ Cmt( Cb("indent_info")
+ * Cc(false) * Cc(true) * Cc("full-code") * Cc(true)
+ , check_continuation_indentation_and_trail)
+
+parsers.check_minimal_indent_and_any_trail =
+ Cmt( Cb("indent_info")
+ * Cc(false) * Cc(false) * Cc("full-any") * Cc(true) * Cc(false)
+ , check_continuation_indentation_and_trail)
+
+parsers.check_minimal_blank_indent_and_any_trail =
+ Cmt( Cb("indent_info")
+ * Cc(false) * Cc(true) * Cc("full-any") * Cc(true) * Cc(false)
+ , check_continuation_indentation_and_trail)
+
+parsers.check_minimal_blank_indent_and_any_trail_no_rem =
+ Cmt( Cb("indent_info")
+ * Cc(false) * Cc(true) * Cc("full-any") * Cc(true) * Cc(true)
+ , check_continuation_indentation_and_trail)
+
+parsers.check_optional_indent_and_any_trail =
+ Cmt( Cb("indent_info")
+ * Cc(true) * Cc(false) * Cc("full-any") * Cc(true) * Cc(false)
+ , check_continuation_indentation_and_trail)
+
+parsers.check_optional_blank_indent_and_any_trail =
+ Cmt( Cb("indent_info")
+ * Cc(true) * Cc(true) * Cc("full-any") * Cc(true) * Cc(false)
+ , check_continuation_indentation_and_trail)
+
+
+parsers.spnlc_noexc = parsers.optionalspace
+ * ( parsers.newline
+ * parsers.check_minimal_indent_and_any_trail)^-1
+
+parsers.spnlc = parsers.optionalspace
+ * (V("EndlineNoSub"))^-1
+
+parsers.spnlc_sep = parsers.optionalspace * V("EndlineNoSub")
+ + parsers.spacechar^1
+
+parsers.only_blank = parsers.spacechar^0
+ * (parsers.newline + parsers.eof)
+
+parsers.commented_line_letter = parsers.linechar
+ + parsers.newline
+ - parsers.backslash
+ - parsers.percent
+parsers.commented_line = Cg(Cc(""), "backslashes")
+ * ((#(parsers.commented_line_letter
+ - parsers.newline)
+ * Cb("backslashes")
+ * Cs(parsers.commented_line_letter
+ - parsers.newline)^1 -- initial
+ * Cg(Cc(""), "backslashes"))
+ + #(parsers.backslash * parsers.backslash)
+ * Cg((parsers.backslash -- even backslash
+ * parsers.backslash)^1, "backslashes")
+ + (parsers.backslash
+ * (#parsers.percent
+ * Cb("backslashes")
+ / function(backslashes)
+ return string.rep("\\", #backslashes / 2)
+ end
+ * C(parsers.percent)
+ + #parsers.commented_line_letter
+ * Cb("backslashes")
+ * Cc("\\")
+ * C(parsers.commented_line_letter))
+ * Cg(Cc(""), "backslashes")))^0
+ * (#parsers.percent
+ * Cb("backslashes")
+ / function(backslashes)
+ return string.rep("\\", #backslashes / 2)
+ end
+ * ((parsers.percent -- comment
+ * parsers.line
+ * #parsers.blankline) -- blank line
+ / "\n"
+ + parsers.percent -- comment
+ * parsers.line
+ * parsers.optionalspace) -- leading spaces
+ + #(parsers.newline)
+ * Cb("backslashes")
+ * C(parsers.newline))
+
+parsers.chunk = parsers.line * (parsers.optionallyindentedline
+ - parsers.blankline)^0
+
+parsers.attribute_key_char = parsers.alphanumeric + S("-_:.")
+parsers.attribute_raw_char = parsers.alphanumeric + S("-_")
+parsers.attribute_key = (parsers.attribute_key_char
+ - parsers.dash - parsers.digit)
+ * parsers.attribute_key_char^0
+parsers.attribute_value = ( (parsers.dquote / "")
+ * (parsers.anyescaped - parsers.dquote)^0
+ * (parsers.dquote / ""))
+ + ( (parsers.squote / "")
+ * (parsers.anyescaped - parsers.squote)^0
+ * (parsers.squote / ""))
+ + ( parsers.anyescaped
+ - parsers.dquote
+ - parsers.rbrace
+ - parsers.space)^0
+parsers.attribute_identifier = parsers.attribute_key_char^1
+parsers.attribute_classname = parsers.letter
+ * parsers.attribute_key_char^0
+parsers.attribute_raw = parsers.attribute_raw_char^1
+
+parsers.attribute = (parsers.dash * Cc(".unnumbered"))
+ + C( parsers.hash
+ * parsers.attribute_identifier)
+ + C( parsers.period
+ * parsers.attribute_classname)
+ + Cs( parsers.attribute_key
+ * parsers.optionalspace
+ * parsers.equal
+ * parsers.optionalspace
+ * parsers.attribute_value)
+parsers.attributes = parsers.lbrace
+ * parsers.optionalspace
+ * parsers.attribute
+ * (parsers.spacechar^1
+ * parsers.attribute)^0
+ * parsers.optionalspace
+ * parsers.rbrace
+
+parsers.raw_attribute = parsers.lbrace
+ * parsers.optionalspace
+ * parsers.equal
+ * C(parsers.attribute_raw)
+ * parsers.optionalspace
+ * parsers.rbrace
+
+-- block followed by 0 or more optionally
+-- indented blocks with first line indented.
+parsers.indented_blocks = function(bl)
+ return Cs( bl
+ * ( parsers.blankline^1
+ * parsers.indent
+ * -parsers.blankline
+ * bl)^0
+ * (parsers.blankline^1 + parsers.eof) )
+end
+local function repeat_between(pattern, min, max)
+ return -pattern^(max + 1) * pattern^min
+end
+
+parsers.hexentity = parsers.ampersand * parsers.hash * C(S("Xx"))
+ * C(repeat_between(parsers.hexdigit, 1, 6))
+ * parsers.semicolon
+parsers.decentity = parsers.ampersand * parsers.hash
+ * C(repeat_between(parsers.digit, 1, 7))
+ * parsers.semicolon
+parsers.tagentity = parsers.ampersand * C(parsers.alphanumeric^1)
+ * parsers.semicolon
+
+parsers.html_entities
+ = parsers.hexentity / entities.hex_entity_with_x_char
+ + parsers.decentity / entities.dec_entity
+ + parsers.tagentity / entities.char_entity
+parsers.bullet = function(bullet_char, interrupting)
+ local allowed_end
+ if interrupting then
+ allowed_end = C(parsers.spacechar^1) * #parsers.linechar
+ else
+ allowed_end = C(parsers.spacechar^1)
+ + #(parsers.newline + parsers.eof)
+ end
+ return parsers.check_trail
+ * Ct(C(bullet_char) * Cc(""))
+ * allowed_end
+end
+
+local function tickbox(interior)
+ return parsers.optionalspace * parsers.lbracket
+ * interior * parsers.rbracket * parsers.spacechar^1
+end
+
+parsers.ticked_box = tickbox(S("xX")) * Cc(1.0)
+parsers.halfticked_box = tickbox(S("./")) * Cc(0.5)
+parsers.unticked_box = tickbox(parsers.spacechar^1) * Cc(0.0)
+
+parsers.openticks = Cg(parsers.backtick^1, "ticks")
+
+local function captures_equal_length(_,i,a,b)
+ return #a == #b and i
+end
+
+parsers.closeticks = Cmt(C(parsers.backtick^1)
+ * Cb("ticks"), captures_equal_length)
+
+parsers.intickschar = (parsers.any - S("\n\r`"))
+ + V("NoSoftLineBreakEndline")
+ + (parsers.backtick^1 - parsers.closeticks)
+
+local function process_inticks(s)
+ s = s:gsub("\n", " ")
+ s = s:gsub("^ (.*) $", "%1")
+ return s
+end
+
+parsers.inticks = parsers.openticks
+ * C(parsers.space^0)
+ * parsers.closeticks
+ + parsers.openticks
+ * Cs(Cs(parsers.intickschar^0) / process_inticks)
+ * parsers.closeticks
+
+-- case-insensitive match (we assume s is lowercase)
+-- must be single byte encoding
+parsers.keyword_exact = function(s)
+ local parser = P(0)
+ for i=1,#s do
+ local c = s:sub(i,i)
+ local m = c .. upper(c)
+ parser = parser * S(m)
+ end
+ return parser
+end
+
+parsers.special_block_keyword =
+ parsers.keyword_exact("pre") +
+ parsers.keyword_exact("script") +
+ parsers.keyword_exact("style") +
+ parsers.keyword_exact("textarea")
+
+parsers.block_keyword =
+ parsers.keyword_exact("address") +
+ parsers.keyword_exact("article") +
+ parsers.keyword_exact("aside") +
+ parsers.keyword_exact("base") +
+ parsers.keyword_exact("basefont") +
+ parsers.keyword_exact("blockquote") +
+ parsers.keyword_exact("body") +
+ parsers.keyword_exact("caption") +
+ parsers.keyword_exact("center") +
+ parsers.keyword_exact("col") +
+ parsers.keyword_exact("colgroup") +
+ parsers.keyword_exact("dd") +
+ parsers.keyword_exact("details") +
+ parsers.keyword_exact("dialog") +
+ parsers.keyword_exact("dir") +
+ parsers.keyword_exact("div") +
+ parsers.keyword_exact("dl") +
+ parsers.keyword_exact("dt") +
+ parsers.keyword_exact("fieldset") +
+ parsers.keyword_exact("figcaption") +
+ parsers.keyword_exact("figure") +
+ parsers.keyword_exact("footer") +
+ parsers.keyword_exact("form") +
+ parsers.keyword_exact("frame") +
+ parsers.keyword_exact("frameset") +
+ parsers.keyword_exact("h1") +
+ parsers.keyword_exact("h2") +
+ parsers.keyword_exact("h3") +
+ parsers.keyword_exact("h4") +
+ parsers.keyword_exact("h5") +
+ parsers.keyword_exact("h6") +
+ parsers.keyword_exact("head") +
+ parsers.keyword_exact("header") +
+ parsers.keyword_exact("hr") +
+ parsers.keyword_exact("html") +
+ parsers.keyword_exact("iframe") +
+ parsers.keyword_exact("legend") +
+ parsers.keyword_exact("li") +
+ parsers.keyword_exact("link") +
+ parsers.keyword_exact("main") +
+ parsers.keyword_exact("menu") +
+ parsers.keyword_exact("menuitem") +
+ parsers.keyword_exact("nav") +
+ parsers.keyword_exact("noframes") +
+ parsers.keyword_exact("ol") +
+ parsers.keyword_exact("optgroup") +
+ parsers.keyword_exact("option") +
+ parsers.keyword_exact("p") +
+ parsers.keyword_exact("param") +
+ parsers.keyword_exact("section") +
+ parsers.keyword_exact("source") +
+ parsers.keyword_exact("summary") +
+ parsers.keyword_exact("table") +
+ parsers.keyword_exact("tbody") +
+ parsers.keyword_exact("td") +
+ parsers.keyword_exact("tfoot") +
+ parsers.keyword_exact("th") +
+ parsers.keyword_exact("thead") +
+ parsers.keyword_exact("title") +
+ parsers.keyword_exact("tr") +
+ parsers.keyword_exact("track") +
+ parsers.keyword_exact("ul")
+
+-- end conditions
+parsers.html_blankline_end_condition
+ = parsers.linechar^0
+ * ( parsers.newline
+ * (parsers.check_minimal_blank_indent_and_any_trail
+ * #parsers.blankline
+ + parsers.check_minimal_indent_and_any_trail)
+ * parsers.linechar^1)^0
+ * (parsers.newline^-1 / "")
+
+local function remove_trailing_blank_lines(s)
+ return s:gsub("[\n\r]+%s*$", "")
+end
+
+parsers.html_until_end = function(end_marker)
+ return Cs(Cs((parsers.newline
+ * (parsers.check_minimal_blank_indent_and_any_trail
+ * #parsers.blankline
+ + parsers.check_minimal_indent_and_any_trail)
+ + parsers.linechar - end_marker)^0
+ * parsers.linechar^0 * parsers.newline^-1)
+ / remove_trailing_blank_lines)
+end
+
+-- attributes
+parsers.html_attribute_spacing = parsers.optionalspace
+ * V("NoSoftLineBreakEndline")
+ * parsers.optionalspace
+ + parsers.spacechar^1
+
+parsers.html_attribute_name = ( parsers.letter
+ + parsers.colon
+ + parsers.underscore)
+ * ( parsers.alphanumeric
+ + parsers.colon
+ + parsers.underscore
+ + parsers.period
+ + parsers.dash)^0
+
+parsers.html_attribute_value = parsers.squote
+ * (parsers.linechar - parsers.squote)^0
+ * parsers.squote
+ + parsers.dquote
+ * (parsers.linechar - parsers.dquote)^0
+ * parsers.dquote
+ + ( parsers.any
+ - parsers.spacechar
+ - parsers.newline
+ - parsers.dquote
+ - parsers.squote
+ - parsers.backtick
+ - parsers.equal
+ - parsers.less
+ - parsers.more)^1
+
+parsers.html_inline_attribute_value = parsers.squote
+ * (V("NoSoftLineBreakEndline")
+ + parsers.any
+ - parsers.blankline^2
+ - parsers.squote)^0
+ * parsers.squote
+ + parsers.dquote
+ * (V("NoSoftLineBreakEndline")
+ + parsers.any
+ - parsers.blankline^2
+ - parsers.dquote)^0
+ * parsers.dquote
+ + (parsers.any
+ - parsers.spacechar
+ - parsers.newline
+ - parsers.dquote
+ - parsers.squote
+ - parsers.backtick
+ - parsers.equal
+ - parsers.less
+ - parsers.more)^1
+
+parsers.html_attribute_value_specification
+ = parsers.optionalspace
+ * parsers.equal
+ * parsers.optionalspace
+ * parsers.html_attribute_value
+
+parsers.html_spnl = parsers.optionalspace
+ * (V("NoSoftLineBreakEndline")
+ * parsers.optionalspace)^-1
+
+parsers.html_inline_attribute_value_specification
+ = parsers.html_spnl
+ * parsers.equal
+ * parsers.html_spnl
+ * parsers.html_inline_attribute_value
+
+parsers.html_attribute
+ = parsers.html_attribute_spacing
+ * parsers.html_attribute_name
+ * parsers.html_inline_attribute_value_specification^-1
+
+parsers.html_non_newline_attribute
+ = parsers.spacechar^1
+ * parsers.html_attribute_name
+ * parsers.html_attribute_value_specification^-1
+
+parsers.nested_breaking_blank = parsers.newline
+ * parsers.check_minimal_blank_indent
+ * parsers.blankline
+
+parsers.html_comment_start = P("<!--")
+
+parsers.html_comment_end = P("-->")
+
+parsers.html_comment
+ = Cs( parsers.html_comment_start
+ * parsers.html_until_end(parsers.html_comment_end))
+
+parsers.html_inline_comment = (parsers.html_comment_start / "")
+ * -P(">") * -P("->")
+ * Cs(( V("NoSoftLineBreakEndline")
+ + parsers.any
+ - parsers.nested_breaking_blank
+ - parsers.html_comment_end)^0)
+ * (parsers.html_comment_end / "")
+
+parsers.html_cdatasection_start = P("<![CDATA[")
+
+parsers.html_cdatasection_end = P("]]>")
+
+parsers.html_cdatasection
+ = Cs( parsers.html_cdatasection_start
+ * parsers.html_until_end(parsers.html_cdatasection_end))
+
+parsers.html_inline_cdatasection
+ = parsers.html_cdatasection_start
+ * Cs(V("NoSoftLineBreakEndline") + parsers.any
+ - parsers.nested_breaking_blank - parsers.html_cdatasection_end)^0
+ * parsers.html_cdatasection_end
+
+parsers.html_declaration_start = P("<!") * parsers.letter
+
+parsers.html_declaration_end = P(">")
+
+parsers.html_declaration
+ = Cs( parsers.html_declaration_start
+ * parsers.html_until_end(parsers.html_declaration_end))
+
+parsers.html_inline_declaration
+ = parsers.html_declaration_start
+ * Cs(V("NoSoftLineBreakEndline") + parsers.any
+ - parsers.nested_breaking_blank - parsers.html_declaration_end)^0
+ * parsers.html_declaration_end
+
+parsers.html_instruction_start = P("<?")
+
+parsers.html_instruction_end = P("?>")
+
+parsers.html_instruction
+ = Cs( parsers.html_instruction_start
+ * parsers.html_until_end(parsers.html_instruction_end))
+
+parsers.html_inline_instruction = parsers.html_instruction_start
+ * Cs( V("NoSoftLineBreakEndline")
+ + parsers.any
+ - parsers.nested_breaking_blank
+ - parsers.html_instruction_end)^0
+ * parsers.html_instruction_end
+
+parsers.html_blankline = parsers.newline
+ * parsers.optionalspace
+ * parsers.newline
+
+parsers.html_tag_start = parsers.less
+
+parsers.html_tag_closing_start = parsers.less
+ * parsers.slash
+
+parsers.html_tag_end = parsers.html_spnl
+ * parsers.more
+
+parsers.html_empty_tag_end = parsers.html_spnl
+ * parsers.slash
+ * parsers.more
+
+-- opening tags
+parsers.html_any_open_inline_tag = parsers.html_tag_start
+ * parsers.keyword
+ * parsers.html_attribute^0
+ * parsers.html_tag_end
+
+parsers.html_any_open_tag = parsers.html_tag_start
+ * parsers.keyword
+ * parsers.html_non_newline_attribute^0
+ * parsers.html_tag_end
+
+parsers.html_open_tag = parsers.html_tag_start
+ * parsers.block_keyword
+ * parsers.html_attribute^0
+ * parsers.html_tag_end
+
+parsers.html_open_special_tag = parsers.html_tag_start
+ * parsers.special_block_keyword
+ * parsers.html_attribute^0
+ * parsers.html_tag_end
+
+-- incomplete tags
+parsers.incomplete_tag_following = parsers.spacechar
+ + parsers.more
+ + parsers.slash * parsers.more
+ + #(parsers.newline + parsers.eof)
+
+parsers.incomplete_special_tag_following = parsers.spacechar
+ + parsers.more
+ + #( parsers.newline
+ + parsers.eof)
+
+parsers.html_incomplete_open_tag = parsers.html_tag_start
+ * parsers.block_keyword
+ * parsers.incomplete_tag_following
+
+parsers.html_incomplete_open_special_tag
+ = parsers.html_tag_start
+ * parsers.special_block_keyword
+ * parsers.incomplete_special_tag_following
+
+parsers.html_incomplete_close_tag = parsers.html_tag_closing_start
+ * parsers.block_keyword
+ * parsers.incomplete_tag_following
+
+parsers.html_incomplete_close_special_tag
+ = parsers.html_tag_closing_start
+ * parsers.special_block_keyword
+ * parsers.incomplete_tag_following
+
+-- closing tags
+parsers.html_close_tag = parsers.html_tag_closing_start
+ * parsers.block_keyword
+ * parsers.html_tag_end
+
+parsers.html_any_close_tag = parsers.html_tag_closing_start
+ * parsers.keyword
+ * parsers.html_tag_end
+
+parsers.html_close_special_tag = parsers.html_tag_closing_start
+ * parsers.special_block_keyword
+ * parsers.html_tag_end
+
+-- empty tags
+parsers.html_any_empty_inline_tag = parsers.html_tag_start
+ * parsers.keyword
+ * parsers.html_attribute^0
+ * parsers.html_empty_tag_end
+
+parsers.html_any_empty_tag = parsers.html_tag_start
+ * parsers.keyword
+ * parsers.html_non_newline_attribute^0
+ * parsers.optionalspace
+ * parsers.slash
+ * parsers.more
+
+parsers.html_empty_tag = parsers.html_tag_start
+ * parsers.block_keyword
+ * parsers.html_attribute^0
+ * parsers.html_empty_tag_end
+
+parsers.html_empty_special_tag = parsers.html_tag_start
+ * parsers.special_block_keyword
+ * parsers.html_attribute^0
+ * parsers.html_empty_tag_end
+
+parsers.html_incomplete_blocks
+ = parsers.html_incomplete_open_tag
+ + parsers.html_incomplete_open_special_tag
+ + parsers.html_incomplete_close_tag
+
+-- parse special html blocks
+parsers.html_blankline_ending_special_block_opening
+ = ( parsers.html_close_special_tag
+ + parsers.html_empty_special_tag)
+ * #( parsers.optionalspace
+ * (parsers.newline + parsers.eof))
+
+parsers.html_blankline_ending_special_block
+ = parsers.html_blankline_ending_special_block_opening
+ * parsers.html_blankline_end_condition
+
+parsers.html_special_block_opening
+ = parsers.html_incomplete_open_special_tag
+ - parsers.html_empty_special_tag
+
+parsers.html_closing_special_block
+ = parsers.html_special_block_opening
+ * parsers.html_until_end(parsers.html_close_special_tag)
+
+parsers.html_special_block
+ = parsers.html_blankline_ending_special_block
+ + parsers.html_closing_special_block
+
+-- parse html blocks
+parsers.html_block_opening = parsers.html_incomplete_open_tag
+ + parsers.html_incomplete_close_tag
+
+parsers.html_block = parsers.html_block_opening
+ * parsers.html_blankline_end_condition
+
+-- parse any html blocks
+parsers.html_any_block_opening
+ = ( parsers.html_any_open_tag
+ + parsers.html_any_close_tag
+ + parsers.html_any_empty_tag)
+ * #(parsers.optionalspace * (parsers.newline + parsers.eof))
+
+parsers.html_any_block = parsers.html_any_block_opening
+ * parsers.html_blankline_end_condition
+
+parsers.html_inline_comment_full = parsers.html_comment_start
+ * -P(">") * -P("->")
+ * Cs(( V("NoSoftLineBreakEndline")
+ + parsers.any - P("--")
+ - parsers.nested_breaking_blank
+ - parsers.html_comment_end)^0)
+ * parsers.html_comment_end
+
+parsers.html_inline_tags = parsers.html_inline_comment_full
+ + parsers.html_any_empty_inline_tag
+ + parsers.html_inline_instruction
+ + parsers.html_inline_cdatasection
+ + parsers.html_inline_declaration
+ + parsers.html_any_open_inline_tag
+ + parsers.html_any_close_tag
+
+parsers.urlchar = parsers.anyescaped
+ - parsers.newline
+ - parsers.more
+
+parsers.auto_link_scheme_part = parsers.alphanumeric
+ + parsers.plus
+ + parsers.period
+ + parsers.dash
+
+parsers.auto_link_scheme = parsers.letter
+ * parsers.auto_link_scheme_part
+ * parsers.auto_link_scheme_part^-30
+
+parsers.absolute_uri = parsers.auto_link_scheme * parsers.colon
+ * ( parsers.any - parsers.spacing
+ - parsers.less - parsers.more)^0
+
+parsers.printable_characters = S(".!#$%&'*+/=?^_`{|}~-")
+
+parsers.email_address_local_part_char = parsers.alphanumeric
+ + parsers.printable_characters
+
+parsers.email_address_local_part
+ = parsers.email_address_local_part_char^1
+
+parsers.email_address_dns_label = parsers.alphanumeric
+ * ( parsers.alphanumeric
+ + parsers.dash)^-62
+ * B(parsers.alphanumeric)
+
+parsers.email_address_domain = parsers.email_address_dns_label
+ * ( parsers.period
+ * parsers.email_address_dns_label)^0
+
+parsers.email_address = parsers.email_address_local_part
+ * parsers.at
+ * parsers.email_address_domain
+
+parsers.auto_link_url = parsers.less
+ * C(parsers.absolute_uri)
+ * parsers.more
+
+parsers.auto_link_email = parsers.less
+ * C(parsers.email_address)
+ * parsers.more
+
+parsers.auto_link_relative_reference = parsers.less
+ * C(parsers.urlchar^1)
+ * parsers.more
+
+parsers.autolink = parsers.auto_link_url
+ + parsers.auto_link_email
+
+-- content in balanced brackets, parentheses, or quotes:
+parsers.bracketed = P{ parsers.lbracket
+ * (( parsers.backslash / "" * parsers.rbracket
+ + parsers.any - (parsers.lbracket
+ + parsers.rbracket
+ + parsers.blankline^2)
+ ) + V(1))^0
+ * parsers.rbracket }
+
+parsers.inparens = P{ parsers.lparent
+ * ((parsers.anyescaped - (parsers.lparent
+ + parsers.rparent
+ + parsers.blankline^2)
+ ) + V(1))^0
+ * parsers.rparent }
+
+parsers.squoted = P{ parsers.squote * parsers.alphanumeric
+ * ((parsers.anyescaped - (parsers.squote
+ + parsers.blankline^2)
+ ) + V(1))^0
+ * parsers.squote }
+
+parsers.dquoted = P{ parsers.dquote * parsers.alphanumeric
+ * ((parsers.anyescaped - (parsers.dquote
+ + parsers.blankline^2)
+ ) + V(1))^0
+ * parsers.dquote }
+
+parsers.link_text = parsers.lbracket
+ * Cs((parsers.alphanumeric^1
+ + parsers.bracketed
+ + parsers.inticks
+ + parsers.autolink
+ + V("InlineHtml")
+ + ( parsers.backslash * parsers.backslash)
+ + ( parsers.backslash
+ * ( parsers.lbracket
+ + parsers.rbracket)
+ + V("NoSoftLineBreakSpace")
+ + V("NoSoftLineBreakEndline")
+ + (parsers.any
+ - ( parsers.newline
+ + parsers.lbracket
+ + parsers.rbracket
+ + parsers.blankline^2))))^0)
+ * parsers.rbracket
+
+parsers.link_label_body = -#(parsers.sp * parsers.rbracket)
+ * #( ( parsers.any
+ - parsers.rbracket)^-999
+ * parsers.rbracket)
+ * Cs((parsers.alphanumeric^1
+ + parsers.inticks
+ + parsers.autolink
+ + V("InlineHtml")
+ + ( parsers.backslash * parsers.backslash)
+ + ( parsers.backslash
+ * ( parsers.lbracket
+ + parsers.rbracket)
+ + V("NoSoftLineBreakSpace")
+ + V("NoSoftLineBreakEndline")
+ + (parsers.any
+ - ( parsers.newline
+ + parsers.lbracket
+ + parsers.rbracket
+ + parsers.blankline^2))))^1)
+
+parsers.link_label = parsers.lbracket
+ * parsers.link_label_body
+ * parsers.rbracket
+
+parsers.inparens_url = P{ parsers.lparent
+ * ((parsers.anyescaped - (parsers.lparent
+ + parsers.rparent
+ + parsers.spacing)
+ ) + V(1))^0
+ * parsers.rparent }
+
+-- url for markdown links, allowing nested brackets:
+parsers.url = parsers.less * Cs((parsers.anyescaped
+ - parsers.newline
+ - parsers.less
+ - parsers.more)^0)
+ * parsers.more
+ + -parsers.less
+ * Cs((parsers.inparens_url + (parsers.anyescaped
+ - parsers.spacing
+ - parsers.lparent
+ - parsers.rparent))^1)
+
+-- quoted text:
+parsers.title_s = parsers.squote
+ * Cs((parsers.html_entities
+ + V("NoSoftLineBreakSpace")
+ + V("NoSoftLineBreakEndline")
+ + ( parsers.anyescaped
+ - parsers.newline
+ - parsers.squote
+ - parsers.blankline^2))^0)
+ * parsers.squote
+
+parsers.title_d = parsers.dquote
+ * Cs((parsers.html_entities
+ + V("NoSoftLineBreakSpace")
+ + V("NoSoftLineBreakEndline")
+ + ( parsers.anyescaped
+ - parsers.newline
+ - parsers.dquote
+ - parsers.blankline^2))^0)
+ * parsers.dquote
+
+parsers.title_p = parsers.lparent
+ * Cs((parsers.html_entities
+ + V("NoSoftLineBreakSpace")
+ + V("NoSoftLineBreakEndline")
+ + ( parsers.anyescaped
+ - parsers.newline
+ - parsers.lparent
+ - parsers.rparent
+ - parsers.blankline^2))^0)
+ * parsers.rparent
+
+parsers.title
+ = parsers.title_d + parsers.title_s + parsers.title_p
+
+parsers.optionaltitle
+ = parsers.spnlc * parsers.title * parsers.spacechar^0 + Cc("")
+
+-- parse a reference definition: [foo]: /bar "title"
+parsers.define_reference_parser = (parsers.check_trail / "")
+ * parsers.link_label * parsers.colon
+ * parsers.spnlc * parsers.url
+ * ( parsers.spnlc_sep * parsers.title
+ * parsers.only_blank
+ + Cc("") * parsers.only_blank)
+parsers.Inline = V("Inline")
+
+-- parse many p between starter and ender
+parsers.between = function(p, starter, ender)
+ local ender2 = B(parsers.nonspacechar) * ender
+ return ( starter
+ * #parsers.nonspacechar
+ * Ct(p * (p - ender2)^0)
+ * ender2)
+end
+
+parsers.lineof = function(c)
+ return ( parsers.check_trail_no_rem
+ * (P(c) * parsers.optionalspace)^3
+ * (parsers.newline + parsers.eof))
+end
+
+parsers.thematic_break_lines = parsers.lineof(parsers.asterisk)
+ + parsers.lineof(parsers.dash)
+ + parsers.lineof(parsers.underscore)
+-- parse Atx heading start and return level
+parsers.heading_start = #parsers.hash * C(parsers.hash^-6)
+ * -parsers.hash / length
+
+-- parse setext header ending and return level
+parsers.heading_level
+ = parsers.nonindentspace * parsers.equal^1
+ * parsers.optionalspace * #parsers.newline * Cc(1)
+ + parsers.nonindentspace * parsers.dash^1
+ * parsers.optionalspace * #parsers.newline * Cc(2)
+
+local function strip_atx_end(s)
+ return s:gsub("%s+#*%s*\n$","")
+end
+
+parsers.atx_heading = parsers.check_trail_no_rem
+ * Cg(parsers.heading_start, "level")
+ * (C( parsers.optionalspace
+ * parsers.hash^0
+ * parsers.optionalspace
+ * parsers.newline)
+ + parsers.spacechar^1
+ * C(parsers.line))
+M.reader = {}
+function M.reader.new(writer, options)
+ local self = {}
+ self.writer = writer
+ self.options = options
+ self.parsers = {}
+ (function(parsers)
+ setmetatable(self.parsers, {
+ __index = function (_, key)
+ return parsers[key]
+ end
+ })
+ end)(parsers)
+ local parsers = self.parsers
+ function self.normalize_tag(tag)
+ tag = util.rope_to_string(tag)
+ tag = tag:gsub("[ \n\r\t]+", " ")
+ tag = tag:gsub("^ ", ""):gsub(" $", "")
+ tag = uni_algos.case.casefold(tag, true, false)
+ return tag
+ end
+ local function iterlines(s, f)
+ local rope = lpeg.match(Ct((parsers.line / f)^1), s)
+ return util.rope_to_string(rope)
+ end
+ if options.preserveTabs then
+ self.expandtabs = function(s) return s end
+ else
+ self.expandtabs = function(s)
+ if s:find("\t") then
+ return iterlines(s, util.expand_tabs_in_line)
+ else
+ return s
+ end
+ end
+ end
+ self.parser_functions = {}
+ self.create_parser = function(name, grammar, toplevel)
+ self.parser_functions[name] = function(str)
+ if toplevel and options.stripIndent then
+ local min_prefix_length, min_prefix = nil, ''
+ str = iterlines(str, function(line)
+ if lpeg.match(parsers.nonemptyline, line) == nil then
+ return line
+ end
+ line = util.expand_tabs_in_line(line)
+ local prefix = lpeg.match(C(parsers.optionalspace), line)
+ local prefix_length = #prefix
+ local is_shorter = min_prefix_length == nil
+ if not is_shorter then
+ is_shorter = prefix_length < min_prefix_length
+ end
+ if is_shorter then
+ min_prefix_length, min_prefix = prefix_length, prefix
+ end
+ return line
+ end)
+ str = str:gsub('^' .. min_prefix, '')
+ end
+ if toplevel and (options.texComments or options.hybrid) then
+ str = lpeg.match(Ct(parsers.commented_line^1), str)
+ str = util.rope_to_string(str)
+ end
+ local res = lpeg.match(grammar(), str)
+ if res == nil then
+ return writer.error(format("%s failed on:\n%s",
+ name, str:sub(1,20)))
+ else
+ return res
+ end
+ end
+ end
+
+ self.create_parser("parse_blocks",
+ function()
+ return parsers.blocks
+ end, true)
+
+ self.create_parser("parse_blocks_nested",
+ function()
+ return parsers.blocks_nested
+ end, false)
+
+ self.create_parser("parse_inlines",
+ function()
+ return parsers.inlines
+ end, false)
+
+ self.create_parser("parse_inlines_no_inline_note",
+ function()
+ return parsers.inlines_no_inline_note
+ end, false)
+
+ self.create_parser("parse_inlines_no_html",
+ function()
+ return parsers.inlines_no_html
+ end, false)
+
+ self.create_parser("parse_inlines_nbsp",
+ function()
+ return parsers.inlines_nbsp
+ end, false)
+ self.create_parser("parse_inlines_no_link_or_emphasis",
+ function()
+ return parsers.inlines_no_link_or_emphasis
+ end, false)
+ parsers.minimally_indented_blankline
+ = parsers.check_minimal_indent * (parsers.blankline / "")
+
+ parsers.minimally_indented_block
+ = parsers.check_minimal_indent * V("Block")
+
+ parsers.minimally_indented_block_or_paragraph
+ = parsers.check_minimal_indent * V("BlockOrParagraph")
+
+ parsers.minimally_indented_paragraph
+ = parsers.check_minimal_indent * V("Paragraph")
+
+ parsers.minimally_indented_plain
+ = parsers.check_minimal_indent * V("Plain")
+
+ parsers.minimally_indented_par_or_plain
+ = parsers.minimally_indented_paragraph
+ + parsers.minimally_indented_plain
+
+ parsers.minimally_indented_par_or_plain_no_blank
+ = parsers.minimally_indented_par_or_plain
+ - parsers.minimally_indented_blankline
+
+ parsers.minimally_indented_ref
+ = parsers.check_minimal_indent * V("Reference")
+
+ parsers.minimally_indented_blank
+ = parsers.check_minimal_indent * V("Blank")
+
+ parsers.conditionally_indented_blankline
+ = parsers.check_minimal_blank_indent * (parsers.blankline / "")
+
+ parsers.minimally_indented_ref_or_block
+ = parsers.minimally_indented_ref
+ + parsers.minimally_indented_block
+ - parsers.minimally_indented_blankline
+
+ parsers.minimally_indented_ref_or_block_or_par
+ = parsers.minimally_indented_ref
+ + parsers.minimally_indented_block_or_paragraph
+ - parsers.minimally_indented_blankline
+
+
+ function parsers.separator_loop(separated_block, paragraph,
+ block_separator, paragraph_separator)
+ return separated_block
+ + block_separator
+ * paragraph
+ * separated_block
+ + paragraph_separator
+ * paragraph
+ end
+
+ function parsers.create_loop_body_pair(separated_block, paragraph,
+ block_separator,
+ paragraph_separator)
+ return {
+ block = parsers.separator_loop(separated_block, paragraph,
+ block_separator, block_separator),
+ par = parsers.separator_loop(separated_block, paragraph,
+ block_separator, paragraph_separator)
+ }
+ end
+
+ parsers.block_sep_group = function(blank)
+ return blank^0 * parsers.eof
+ + ( blank^2 / writer.paragraphsep
+ + blank^0 / writer.interblocksep
+ )
+ end
+
+ parsers.par_sep_group = function(blank)
+ return blank^0 * parsers.eof
+ + blank^0 / writer.paragraphsep
+ end
+
+ parsers.sep_group_no_output = function(blank)
+ return blank^0 * parsers.eof
+ + blank^0
+ end
+
+ parsers.content_blank = parsers.minimally_indented_blankline
+
+ parsers.ref_or_block_separated
+ = parsers.sep_group_no_output(parsers.content_blank)
+ * ( parsers.minimally_indented_ref
+ - parsers.content_blank)
+ + parsers.block_sep_group(parsers.content_blank)
+ * ( parsers.minimally_indented_block
+ - parsers.content_blank)
+
+ parsers.loop_body_pair =
+ parsers.create_loop_body_pair(
+ parsers.ref_or_block_separated,
+ parsers.minimally_indented_par_or_plain_no_blank,
+ parsers.block_sep_group(parsers.content_blank),
+ parsers.par_sep_group(parsers.content_blank))
+
+ parsers.content_loop = ( V("Block")
+ * parsers.loop_body_pair.block^0
+ + (V("Paragraph") + V("Plain"))
+ * parsers.ref_or_block_separated
+ * parsers.loop_body_pair.block^0
+ + (V("Paragraph") + V("Plain"))
+ * parsers.loop_body_pair.par^0)
+ * parsers.content_blank^0
+
+ parsers.indented_content = function()
+ return Ct( (V("Reference") + (parsers.blankline / ""))
+ * parsers.content_blank^0
+ * parsers.check_minimal_indent
+ * parsers.content_loop
+ + (V("Reference") + (parsers.blankline / ""))
+ * parsers.content_blank^0
+ + parsers.content_loop)
+ end
+
+ parsers.add_indent = function(pattern, name, breakable)
+ return Cg(Cmt( Cb("indent_info")
+ * Ct(pattern)
+ * ( #parsers.linechar -- check if starter is blank
+ * Cc(false) + Cc(true))
+ * Cc(name)
+ * Cc(breakable),
+ process_starter_indent), "indent_info")
+ end
+
+ if options.hashEnumerators then
+ parsers.dig = parsers.digit + parsers.hash
+ else
+ parsers.dig = parsers.digit
+ end
+
+ parsers.enumerator = function(delimiter_type, interrupting)
+ local delimiter_range
+ local allowed_end
+ if interrupting then
+ delimiter_range = P("1")
+ allowed_end = C(parsers.spacechar^1) * #parsers.linechar
+ else
+ delimiter_range = parsers.dig * parsers.dig^-8
+ allowed_end = C(parsers.spacechar^1)
+ + #(parsers.newline + parsers.eof)
+ end
+
+ return parsers.check_trail
+ * Ct(C(delimiter_range) * C(delimiter_type))
+ * allowed_end
+ end
+
+ parsers.starter = parsers.bullet(parsers.dash)
+ + parsers.bullet(parsers.asterisk)
+ + parsers.bullet(parsers.plus)
+ + parsers.enumerator(parsers.period)
+ + parsers.enumerator(parsers.rparent)
+
+ parsers.blockquote_start
+ = parsers.check_trail
+ * C(parsers.more)
+ * C(parsers.spacechar^0)
+
+ parsers.blockquote_body
+ = parsers.add_indent(parsers.blockquote_start, "bq", true)
+ * parsers.indented_content()
+ * remove_indent("bq")
+
+ if not options.breakableBlockquotes then
+ parsers.blockquote_body
+ = parsers.add_indent(parsers.blockquote_start, "bq", false)
+ * parsers.indented_content()
+ * remove_indent("bq")
+ end
+ local function parse_content_part(content_part)
+ local rope = util.rope_to_string(content_part)
+ local parsed
+ = self.parser_functions.parse_inlines_no_link_or_emphasis(rope)
+ parsed.indent_info = nil
+ return parsed
+ end
+
+ local collect_emphasis_content =
+ function(t, opening_index, closing_index)
+ local content = {}
+
+ local content_part = {}
+ for i = opening_index, closing_index do
+ local value = t[i]
+
+ if value.rendered ~= nil then
+ content[#content + 1] = parse_content_part(content_part)
+ content_part = {}
+ content[#content + 1] = value.rendered
+ value.rendered = nil
+ else
+ if value.type == "delimiter"
+ and value.element == "emphasis" then
+ if value.is_active then
+ content_part[#content_part + 1]
+ = string.rep(value.character, value.current_count)
+ end
+ else
+ content_part[#content_part + 1] = value.content
+ end
+ value.content = ''
+ value.is_active = false
+ end
+ end
+
+ if next(content_part) ~= nil then
+ content[#content + 1] = parse_content_part(content_part)
+ end
+
+ return content
+ end
+
+ local function fill_emph(t, opening_index, closing_index)
+ local content
+ = collect_emphasis_content(t, opening_index + 1,
+ closing_index - 1)
+ t[opening_index + 1].is_active = true
+ t[opening_index + 1].rendered = writer.emphasis(content)
+ end
+
+ local function fill_strong(t, opening_index, closing_index)
+ local content
+ = collect_emphasis_content(t, opening_index + 1,
+ closing_index - 1)
+ t[opening_index + 1].is_active = true
+ t[opening_index + 1].rendered = writer.strong(content)
+ end
+
+ local function breaks_three_rule(opening_delimiter, closing_delimiter)
+ return ( opening_delimiter.is_closing
+ or closing_delimiter.is_opening)
+ and (( opening_delimiter.original_count
+ + closing_delimiter.original_count) % 3 == 0)
+ and ( opening_delimiter.original_count % 3 ~= 0
+ or closing_delimiter.original_count % 3 ~= 0)
+ end
+
+ local find_emphasis_opener = function(t, bottom_index, latest_index,
+ character, closing_delimiter)
+ for i = latest_index, bottom_index, -1 do
+ local value = t[i]
+ if value.is_active and
+ value.is_opening and
+ value.type == "delimiter" and
+ value.element == "emphasis" and
+ (value.character == character) and
+ (value.current_count > 0) then
+ if not breaks_three_rule(value, closing_delimiter) then
+ return i
+ end
+ end
+ end
+ end
+
+ local function process_emphasis(t, opening_index, closing_index)
+ for i = opening_index, closing_index do
+ local value = t[i]
+ if value.type == "delimiter" and value.element == "emphasis" then
+ local delimiter_length = string.len(value.content)
+ value.character = string.sub(value.content, 1, 1)
+ value.current_count = delimiter_length
+ value.original_count = delimiter_length
+ end
+ end
+
+ local openers_bottom = {
+ ['*'] = {
+ [true] = {opening_index, opening_index, opening_index},
+ [false] = {opening_index, opening_index, opening_index}
+ },
+ ['_'] = {
+ [true] = {opening_index, opening_index, opening_index},
+ [false] = {opening_index, opening_index, opening_index}
+ }
+ }
+
+ local current_position = opening_index
+ local max_position = closing_index
+
+ while current_position <= max_position do
+ local value = t[current_position]
+
+ if value.type ~= "delimiter" or
+ value.element ~= "emphasis" or
+ not value.is_active or
+ not value.is_closing or
+ (value.current_count <= 0) then
+ current_position = current_position + 1
+ goto continue
+ end
+
+ local character = value.character
+ local is_opening = value.is_opening
+ local closing_length_modulo_three = value.original_count % 3
+
+ local current_openers_bottom
+ = openers_bottom[character][is_opening]
+ [closing_length_modulo_three + 1]
+
+ local opener_position
+ = find_emphasis_opener(t, current_openers_bottom,
+ current_position - 1, character, value)
+
+ if (opener_position == nil) then
+ openers_bottom[character][is_opening]
+ [closing_length_modulo_three + 1]
+ = current_position
+ current_position = current_position + 1
+ goto continue
+ end
+
+ local opening_delimiter = t[opener_position]
+
+ local current_opening_count = opening_delimiter.current_count
+ local current_closing_count = t[current_position].current_count
+
+ if (current_opening_count >= 2)
+ and (current_closing_count >= 2) then
+ opening_delimiter.current_count = current_opening_count - 2
+ t[current_position].current_count = current_closing_count - 2
+ fill_strong(t, opener_position, current_position)
+ else
+ opening_delimiter.current_count = current_opening_count - 1
+ t[current_position].current_count = current_closing_count - 1
+ fill_emph(t, opener_position, current_position)
+ end
+
+ ::continue::
+ end
+ end
+
+ local cont = lpeg.R("\128\191") -- continuation byte
+
+ local function utf8_by_byte_count(n)
+ if (n == 1) then
+ return lpeg.R("\0\127")
+ end
+ if (n == 2) then
+ return lpeg.R("\194\223") * cont
+ end
+ if (n == 3) then
+ return lpeg.R("\224\239") * cont * cont
+ end
+ if (n == 4) then
+ return lpeg.R("\240\244") * cont * cont * cont
+ end
+ end
+ local function check_unicode_type(s, i, start_pos, end_pos, chartype)
+ local c
+ local char_length
+ for pos = start_pos, end_pos, 1 do
+ if (start_pos < 0) then
+ char_length = -pos
+ else
+ char_length = pos + 1
+ end
+
+ if (chartype == "punctuation") then
+ if lpeg.match(parsers.punctuation[char_length], s, i+pos) then
+ return i
+ end
+ else
+ c = lpeg.match({ C(utf8_by_byte_count(char_length)) },s,i+pos)
+ if (c ~= nil) and (unicode.utf8.match(c, chartype)) then
+ return i
+ end
+ end
+ end
+ end
+
+ local function check_preceding_unicode_punctuation(s, i)
+ return check_unicode_type(s, i, -4, -1, "punctuation")
+ end
+
+ local function check_preceding_unicode_whitespace(s, i)
+ return check_unicode_type(s, i, -4, -1, "%s")
+ end
+
+ local function check_following_unicode_punctuation(s, i)
+ return check_unicode_type(s, i, 0, 3, "punctuation")
+ end
+
+ local function check_following_unicode_whitespace(s, i)
+ return check_unicode_type(s, i, 0, 3, "%s")
+ end
+
+ parsers.unicode_preceding_punctuation
+ = B(parsers.escapable)
+ + Cmt(parsers.succeed, check_preceding_unicode_punctuation)
+
+ parsers.unicode_preceding_whitespace
+ = Cmt(parsers.succeed, check_preceding_unicode_whitespace)
+
+ parsers.unicode_following_punctuation
+ = #parsers.escapable
+ + Cmt(parsers.succeed, check_following_unicode_punctuation)
+
+ parsers.unicode_following_whitespace
+ = Cmt(parsers.succeed, check_following_unicode_whitespace)
+
+ parsers.delimiter_run = function(character)
+ return (B(parsers.backslash * character) + -B(character))
+ * character^1
+ * -#character
+ end
+
+ parsers.left_flanking_delimiter_run = function(character)
+ return (B( parsers.any)
+ * ( parsers.unicode_preceding_punctuation
+ + parsers.unicode_preceding_whitespace)
+ + -B(parsers.any))
+ * parsers.delimiter_run(character)
+ * parsers.unicode_following_punctuation
+ + parsers.delimiter_run(character)
+ * -#( parsers.unicode_following_punctuation
+ + parsers.unicode_following_whitespace
+ + parsers.eof)
+ end
+
+ parsers.right_flanking_delimiter_run = function(character)
+ return parsers.unicode_preceding_punctuation
+ * parsers.delimiter_run(character)
+ * ( parsers.unicode_following_punctuation
+ + parsers.unicode_following_whitespace
+ + parsers.eof)
+ + (B(parsers.any)
+ * -( parsers.unicode_preceding_punctuation
+ + parsers.unicode_preceding_whitespace))
+ * parsers.delimiter_run(character)
+ end
+
+ if options.underscores then
+ parsers.emph_start
+ = parsers.left_flanking_delimiter_run(parsers.asterisk)
+ + ( -#parsers.right_flanking_delimiter_run(parsers.underscore)
+ + ( parsers.unicode_preceding_punctuation
+ * #parsers.right_flanking_delimiter_run(parsers.underscore)))
+ * parsers.left_flanking_delimiter_run(parsers.underscore)
+
+ parsers.emph_end
+ = parsers.right_flanking_delimiter_run(parsers.asterisk)
+ + ( -#parsers.left_flanking_delimiter_run(parsers.underscore)
+ + #( parsers.left_flanking_delimiter_run(parsers.underscore)
+ * parsers.unicode_following_punctuation))
+ * parsers.right_flanking_delimiter_run(parsers.underscore)
+ else
+ parsers.emph_start
+ = parsers.left_flanking_delimiter_run(parsers.asterisk)
+
+ parsers.emph_end
+ = parsers.right_flanking_delimiter_run(parsers.asterisk)
+ end
+
+ parsers.emph_capturing_open_and_close
+ = #parsers.emph_start * #parsers.emph_end
+ * Ct( Cg(Cc("delimiter"), "type")
+ * Cg(Cc("emphasis"), "element")
+ * Cg(C(parsers.emph_start), "content")
+ * Cg(Cc(true), "is_opening")
+ * Cg(Cc(true), "is_closing"))
+
+ parsers.emph_capturing_open = Ct( Cg(Cc("delimiter"), "type")
+ * Cg(Cc("emphasis"), "element")
+ * Cg(C(parsers.emph_start), "content")
+ * Cg(Cc(true), "is_opening")
+ * Cg(Cc(false), "is_closing"))
+
+ parsers.emph_capturing_close = Ct( Cg(Cc("delimiter"), "type")
+ * Cg(Cc("emphasis"), "element")
+ * Cg(C(parsers.emph_end), "content")
+ * Cg(Cc(false), "is_opening")
+ * Cg(Cc(true), "is_closing"))
+
+ parsers.emph_open_or_close = parsers.emph_capturing_open_and_close
+ + parsers.emph_capturing_open
+ + parsers.emph_capturing_close
+
+ parsers.emph_open = parsers.emph_capturing_open_and_close
+ + parsers.emph_capturing_open
+
+ parsers.emph_close = parsers.emph_capturing_open_and_close
+ + parsers.emph_capturing_close
+
+ -- List of references defined in the document
+ local references
+
+ -- List of note references defined in the document
+ parsers.rawnotes = {}
+
+ function self.register_link(_, tag, url, title,
+ attributes)
+ local normalized_tag = self.normalize_tag(tag)
+ if references[normalized_tag] == nil then
+ references[normalized_tag] = {
+ url = url,
+ title = title,
+ attributes = attributes
+ }
+ end
+ return ""
+ end
+
+ function self.lookup_reference(tag)
+ return references[self.normalize_tag(tag)]
+ end
+
+ function self.lookup_note_reference(tag)
+ return parsers.rawnotes[self.normalize_tag(tag)]
+ end
+
+ parsers.title_s_direct_ref = parsers.squote
+ * Cs((parsers.html_entities
+ + ( parsers.anyescaped
+ - parsers.squote
+ - parsers.blankline^2))^0)
+ * parsers.squote
+
+ parsers.title_d_direct_ref = parsers.dquote
+ * Cs((parsers.html_entities
+ + ( parsers.anyescaped
+ - parsers.dquote
+ - parsers.blankline^2))^0)
+ * parsers.dquote
+
+ parsers.title_p_direct_ref = parsers.lparent
+ * Cs((parsers.html_entities
+ + ( parsers.anyescaped
+ - parsers.lparent
+ - parsers.rparent
+ - parsers.blankline^2))^0)
+ * parsers.rparent
+
+ parsers.title_direct_ref = parsers.title_s_direct_ref
+ + parsers.title_d_direct_ref
+ + parsers.title_p_direct_ref
+
+ parsers.inline_direct_ref_inside = parsers.lparent * parsers.spnl
+ * Cg(parsers.url + Cc(""), "url")
+ * parsers.spnl
+ * Cg( parsers.title_direct_ref
+ + Cc(""), "title")
+ * parsers.spnl * parsers.rparent
+
+ parsers.inline_direct_ref = parsers.lparent * parsers.spnlc
+ * Cg(parsers.url + Cc(""), "url")
+ * parsers.spnlc
+ * Cg(parsers.title + Cc(""), "title")
+ * parsers.spnlc * parsers.rparent
+
+ parsers.empty_link = parsers.lbracket
+ * parsers.rbracket
+
+ parsers.inline_link = parsers.link_text
+ * parsers.inline_direct_ref
+
+ parsers.full_link = parsers.link_text
+ * parsers.link_label
+
+ parsers.shortcut_link = parsers.link_label
+ * -(parsers.empty_link + parsers.link_label)
+
+ parsers.collapsed_link = parsers.link_label
+ * parsers.empty_link
+
+ parsers.image_opening = #(parsers.exclamation * parsers.inline_link)
+ * Cg(Cc("inline"), "link_type")
+ + #(parsers.exclamation * parsers.full_link)
+ * Cg(Cc("full"), "link_type")
+ + #( parsers.exclamation
+ * parsers.collapsed_link)
+ * Cg(Cc("collapsed"), "link_type")
+ + #(parsers.exclamation * parsers.shortcut_link)
+ * Cg(Cc("shortcut"), "link_type")
+ + #(parsers.exclamation * parsers.empty_link)
+ * Cg(Cc("empty"), "link_type")
+
+ parsers.link_opening = #parsers.inline_link
+ * Cg(Cc("inline"), "link_type")
+ + #parsers.full_link
+ * Cg(Cc("full"), "link_type")
+ + #parsers.collapsed_link
+ * Cg(Cc("collapsed"), "link_type")
+ + #parsers.shortcut_link
+ * Cg(Cc("shortcut"), "link_type")
+ + #parsers.empty_link
+ * Cg(Cc("empty_link"), "link_type")
+ + #parsers.link_text
+ * Cg(Cc("link_text"), "link_type")
+
+ parsers.note_opening = #(parsers.circumflex * parsers.link_text)
+ * Cg(Cc("note_inline"), "link_type")
+
+ parsers.raw_note_opening = #( parsers.lbracket
+ * parsers.circumflex
+ * parsers.link_label_body
+ * parsers.rbracket)
+ * Cg(Cc("raw_note"), "link_type")
+
+ local inline_note_element = Cg(Cc("note"), "element")
+ * parsers.note_opening
+ * Cg( parsers.circumflex
+ * parsers.lbracket, "content")
+
+ local image_element = Cg(Cc("image"), "element")
+ * parsers.image_opening
+ * Cg( parsers.exclamation
+ * parsers.lbracket, "content")
+
+ local note_element = Cg(Cc("note"), "element")
+ * parsers.raw_note_opening
+ * Cg( parsers.lbracket
+ * parsers.circumflex, "content")
+
+ local link_element = Cg(Cc("link"), "element")
+ * parsers.link_opening
+ * Cg(parsers.lbracket, "content")
+
+ local opening_elements = parsers.fail
+
+ if options.inlineNotes then
+ opening_elements = opening_elements + inline_note_element
+ end
+
+ opening_elements = opening_elements + image_element
+
+ if options.notes then
+ opening_elements = opening_elements + note_element
+ end
+
+ opening_elements = opening_elements + link_element
+
+ parsers.link_image_opening = Ct( Cg(Cc("delimiter"), "type")
+ * Cg(Cc(true), "is_opening")
+ * Cg(Cc(false), "is_closing")
+ * opening_elements)
+
+ parsers.link_image_closing = Ct( Cg(Cc("delimiter"), "type")
+ * Cg(Cc("link"), "element")
+ * Cg(Cc(false), "is_opening")
+ * Cg(Cc(true), "is_closing")
+ * ( Cg(Cc(true), "is_direct")
+ * Cg( parsers.rbracket
+ * #parsers.inline_direct_ref,
+ "content")
+ + Cg(Cc(false), "is_direct")
+ * Cg(parsers.rbracket, "content")))
+
+ parsers.link_image_open_or_close = parsers.link_image_opening
+ + parsers.link_image_closing
+
+ if options.html then
+ parsers.link_emph_precedence = parsers.inticks
+ + parsers.autolink
+ + parsers.html_inline_tags
+ else
+ parsers.link_emph_precedence = parsers.inticks
+ + parsers.autolink
+ end
+
+ parsers.link_and_emph_endline = parsers.newline
+ * ((parsers.check_minimal_indent
+ * -V("EndlineExceptions")
+ + parsers.check_optional_indent
+ * -V("EndlineExceptions")
+ * -parsers.starter) / "")
+ * parsers.spacechar^0 / "\n"
+
+ parsers.link_and_emph_content
+ = Ct( Cg(Cc("content"), "type")
+ * Cg(Cs(( parsers.link_emph_precedence
+ + parsers.backslash * parsers.any
+ + parsers.link_and_emph_endline
+ + (parsers.linechar
+ - parsers.blankline^2
+ - parsers.link_image_open_or_close
+ - parsers.emph_open_or_close))^0), "content"))
+
+ parsers.link_and_emph_table
+ = (parsers.link_image_opening + parsers.emph_open)
+ * parsers.link_and_emph_content
+ * ((parsers.link_image_open_or_close + parsers.emph_open_or_close)
+ * parsers.link_and_emph_content)^1
+
+ local function collect_link_content(t, opening_index, closing_index)
+ local content = {}
+ for i = opening_index, closing_index do
+ content[#content + 1] = t[i].content
+ end
+ return util.rope_to_string(content)
+ end
+
+ local function find_link_opener(t, bottom_index, latest_index)
+ for i = latest_index, bottom_index, -1 do
+ local value = t[i]
+ if value.type == "delimiter" and
+ value.is_opening and
+ ( value.element == "link"
+ or value.element == "image"
+ or value.element == "note")
+ and not value.removed then
+ if value.is_active then
+ return i
+ end
+ value.removed = true
+ return nil
+ end
+ end
+ end
+
+ local function find_next_link_closing_index(t, latest_index)
+ for i = latest_index, #t do
+ local value = t[i]
+ if value.is_closing and
+ value.element == "link" and
+ not value.removed then
+ return i
+ end
+ end
+ end
+
+ local function disable_previous_link_openers(t, opening_index)
+ if t[opening_index].element == "image" then
+ return
+ end
+
+ for i = opening_index, 1, -1 do
+ local value = t[i]
+ if value.is_active and
+ value.type == "delimiter" and
+ value.is_opening and
+ value.element == "link" then
+ value.is_active = false
+ end
+ end
+ end
+
+ local function disable_range(t, opening_index, closing_index)
+ for i = opening_index, closing_index do
+ local value = t[i]
+ if value.is_active then
+ value.is_active = false
+ if value.type == "delimiter" then
+ value.removed = true
+ end
+ end
+ end
+ end
+
+ local delete_parsed_content_in_range =
+ function(t, opening_index, closing_index)
+ for i = opening_index, closing_index do
+ t[i].rendered = nil
+ end
+ end
+
+ local function empty_content_in_range(t, opening_index, closing_index)
+ for i = opening_index, closing_index do
+ t[i].content = ''
+ end
+ end
+
+ local function join_attributes(reference_attributes, own_attributes)
+ local merged_attributes = {}
+ for _, attribute in ipairs(reference_attributes or {}) do
+ table.insert(merged_attributes, attribute)
+ end
+ for _, attribute in ipairs(own_attributes or {}) do
+ table.insert(merged_attributes, attribute)
+ end
+ if next(merged_attributes) == nil then
+ merged_attributes = nil
+ end
+ return merged_attributes
+ end
+
+ local render_link_or_image =
+ function(t, opening_index, closing_index, content_end_index,
+ reference)
+ process_emphasis(t, opening_index, content_end_index)
+ local mapped = collect_emphasis_content(t, opening_index + 1,
+ content_end_index - 1)
+
+ local rendered = {}
+ if (t[opening_index].element == "link") then
+ rendered = writer.link(mapped, reference.url,
+ reference.title, reference.attributes)
+ end
+
+ if (t[opening_index].element == "image") then
+ rendered = writer.image(mapped, reference.url, reference.title,
+ reference.attributes)
+ end
+
+ if (t[opening_index].element == "note") then
+ if (t[opening_index].link_type == "note_inline") then
+ rendered = writer.note(mapped)
+ end
+ if (t[opening_index].link_type == "raw_note") then
+ rendered = writer.note(reference)
+ end
+ end
+
+ t[opening_index].rendered = rendered
+ delete_parsed_content_in_range(t, opening_index + 1,
+ closing_index)
+ empty_content_in_range(t, opening_index, closing_index)
+ disable_previous_link_openers(t, opening_index)
+ disable_range(t, opening_index, closing_index)
+ end
+
+ local resolve_inline_following_content =
+ function(t, closing_index, match_reference, match_link_attributes)
+ local content = ""
+ for i = closing_index + 1, #t do
+ content = content .. t[i].content
+ end
+
+ local matching_content = parsers.succeed
+
+ if match_reference then
+ matching_content = matching_content
+ * parsers.inline_direct_ref_inside
+ end
+
+ if match_link_attributes then
+ matching_content = matching_content
+ * Cg(Ct(parsers.attributes^-1), "attributes")
+ end
+
+ local matched = lpeg.match(Ct( matching_content
+ * Cg(Cp(), "end_position")), content)
+
+ local matched_count = matched.end_position - 1
+ for i = closing_index + 1, #t do
+ local value = t[i]
+
+ local chars_left = matched_count
+ matched_count = matched_count - #value.content
+
+ if matched_count <= 0 then
+ value.content = value.content:sub(chars_left + 1)
+ break
+ end
+
+ value.content = ''
+ value.is_active = false
+ end
+
+ local attributes = matched.attributes
+ if attributes == nil or next(attributes) == nil then
+ attributes = nil
+ end
+
+ return {
+ url = matched.url or "",
+ title = matched.title or "",
+ attributes = attributes
+ }
+ end
+
+ local function resolve_inline_link(t, opening_index, closing_index)
+ local inline_content
+ = resolve_inline_following_content(t, closing_index, true,
+ t.match_link_attributes)
+ render_link_or_image(t, opening_index, closing_index,
+ closing_index, inline_content)
+ end
+
+ local resolve_note_inline_link =
+ function(t, opening_index, closing_index)
+ local inline_content
+ = resolve_inline_following_content(t, closing_index,
+ false, false)
+ render_link_or_image(t, opening_index, closing_index,
+ closing_index, inline_content)
+ end
+
+ local function resolve_shortcut_link(t, opening_index, closing_index)
+ local content
+ = collect_link_content(t, opening_index + 1, closing_index - 1)
+ local r = self.lookup_reference(content)
+
+ if r then
+ local inline_content
+ = resolve_inline_following_content(t, closing_index, false,
+ t.match_link_attributes)
+ r.attributes
+ = join_attributes(r.attributes, inline_content.attributes)
+ render_link_or_image(t, opening_index, closing_index,
+ closing_index, r)
+ end
+ end
+
+ local function resolve_raw_note_link(t, opening_index, closing_index)
+ local content
+ = collect_link_content(t, opening_index + 1, closing_index - 1)
+ local r = self.lookup_note_reference(content)
+
+ if r then
+ local parsed_ref = self.parser_functions.parse_blocks_nested(r)
+ render_link_or_image(t, opening_index, closing_index,
+ closing_index, parsed_ref)
+ end
+ end
+
+ local function resolve_full_link(t, opening_index, closing_index)
+ local next_link_closing_index
+ = find_next_link_closing_index(t, closing_index + 4)
+ local next_link_content
+ = collect_link_content(t, closing_index + 3,
+ next_link_closing_index - 1)
+ local r = self.lookup_reference(next_link_content)
+
+ if r then
+ local inline_content
+ = resolve_inline_following_content(t, next_link_closing_index,
+ false,
+ t.match_link_attributes)
+ r.attributes
+ = join_attributes(r.attributes, inline_content.attributes)
+ render_link_or_image(t, opening_index, next_link_closing_index,
+ closing_index, r)
+ end
+ end
+
+ local function resolve_collapsed_link(t, opening_index, closing_index)
+ local next_link_closing_index
+ = find_next_link_closing_index(t, closing_index + 4)
+ local content
+ = collect_link_content(t, opening_index + 1, closing_index - 1)
+ local r = self.lookup_reference(content)
+
+ if r then
+ local inline_content
+ = resolve_inline_following_content(t, closing_index, false,
+ t.match_link_attributes)
+ r.attributes
+ = join_attributes(r.attributes, inline_content.attributes)
+ render_link_or_image(t, opening_index, next_link_closing_index,
+ closing_index, r)
+ end
+ end
+
+ local function process_links_and_emphasis(t)
+ for _,value in ipairs(t) do
+ value.is_active = true
+ end
+
+ for i,value in ipairs(t) do
+ if not value.is_closing
+ or value.type ~= "delimiter"
+ or not ( value.element == "link"
+ or value.element == "image"
+ or value.element == "note")
+ or value.removed then
+ goto continue
+ end
+
+ local opener_position = find_link_opener(t, 1, i - 1)
+ if (opener_position == nil) then
+ goto continue
+ end
+
+ local opening_delimiter = t[opener_position]
+ opening_delimiter.removed = true
+
+ local link_type = opening_delimiter.link_type
+
+ if (link_type == "inline") then
+ resolve_inline_link(t, opener_position, i)
+ end
+ if (link_type == "shortcut") then
+ resolve_shortcut_link(t, opener_position, i)
+ end
+ if (link_type == "full") then
+ resolve_full_link(t, opener_position, i)
+ end
+ if (link_type == "collapsed") then
+ resolve_collapsed_link(t, opener_position, i)
+ end
+ if (link_type == "note_inline") then
+ resolve_note_inline_link(t, opener_position, i)
+ end
+ if (link_type == "raw_note") then
+ resolve_raw_note_link(t, opener_position, i)
+ end
+
+ ::continue::
+ end
+
+ t[#t].content = t[#t].content:gsub("%s*$","")
+
+ process_emphasis(t, 1, #t)
+ local final_result = collect_emphasis_content(t, 1, #t)
+ return final_result
+ end
+
+ function self.defer_link_and_emphasis_processing(delimiter_table)
+ return writer.defer_call(function()
+ return process_links_and_emphasis(delimiter_table)
+ end)
+ end
+
+ parsers.Str = ( parsers.normalchar
+ * (parsers.normalchar + parsers.at)^0)
+ / writer.string
+
+ parsers.Symbol = (parsers.backtick^1 + V("SpecialChar"))
+ / writer.string
+
+ parsers.Ellipsis = P("...") / writer.ellipsis
+
+ parsers.Smart = parsers.Ellipsis
+
+ parsers.Code = parsers.inticks / writer.code
+
+ if options.blankBeforeBlockquote then
+ parsers.bqstart = parsers.fail
+ else
+ parsers.bqstart = parsers.blockquote_start
+ end
+
+ if options.blankBeforeHeading then
+ parsers.headerstart = parsers.fail
+ else
+ parsers.headerstart = parsers.atx_heading
+ end
+
+ if options.blankBeforeList then
+ parsers.interrupting_bullets = parsers.fail
+ parsers.interrupting_enumerators = parsers.fail
+ else
+ parsers.interrupting_bullets
+ = parsers.bullet(parsers.dash, true)
+ + parsers.bullet(parsers.asterisk, true)
+ + parsers.bullet(parsers.plus, true)
+
+ parsers.interrupting_enumerators
+ = parsers.enumerator(parsers.period, true)
+ + parsers.enumerator(parsers.rparent, true)
+ end
+
+ if options.html then
+ parsers.html_interrupting
+ = parsers.check_trail
+ * ( parsers.html_incomplete_open_tag
+ + parsers.html_incomplete_close_tag
+ + parsers.html_incomplete_open_special_tag
+ + parsers.html_comment_start
+ + parsers.html_cdatasection_start
+ + parsers.html_declaration_start
+ + parsers.html_instruction_start
+ - parsers.html_close_special_tag
+ - parsers.html_empty_special_tag)
+ else
+ parsers.html_interrupting = parsers.fail
+ end
+
+ parsers.EndlineExceptions
+ = parsers.blankline -- paragraph break
+ + parsers.eof -- end of document
+ + parsers.bqstart
+ + parsers.thematic_break_lines
+ + parsers.interrupting_bullets
+ + parsers.interrupting_enumerators
+ + parsers.headerstart
+ + parsers.html_interrupting
+
+ parsers.NoSoftLineBreakEndlineExceptions = parsers.EndlineExceptions
+
+ parsers.endline = parsers.newline
+ * (parsers.check_minimal_indent
+ * -V("EndlineExceptions")
+ + parsers.check_optional_indent
+ * -V("EndlineExceptions")
+ * -parsers.starter) / function(_) return end
+ * parsers.spacechar^0
+
+ parsers.Endline = parsers.endline
+ / writer.soft_line_break
+
+ parsers.EndlineNoSub = parsers.endline
+
+ parsers.NoSoftLineBreakEndline
+ = parsers.newline
+ * (parsers.check_minimal_indent
+ * -V("NoSoftLineBreakEndlineExceptions")
+ + parsers.check_optional_indent
+ * -V("NoSoftLineBreakEndlineExceptions")
+ * -parsers.starter)
+ * parsers.spacechar^0
+ / writer.space
+
+ parsers.EndlineBreak = parsers.backslash * parsers.Endline
+ / writer.hard_line_break
+
+ parsers.OptionalIndent
+ = parsers.spacechar^1 / writer.space
+
+ parsers.Space = parsers.spacechar^2 * parsers.Endline
+ / writer.hard_line_break
+ + parsers.spacechar^1
+ * parsers.Endline^-1
+ * parsers.eof / self.expandtabs
+ + parsers.spacechar^1 * parsers.Endline
+ / writer.soft_line_break
+ + parsers.spacechar^1
+ * -parsers.newline / self.expandtabs
+
+ parsers.NoSoftLineBreakSpace
+ = parsers.spacechar^2 * parsers.Endline
+ / writer.hard_line_break
+ + parsers.spacechar^1
+ * parsers.Endline^-1
+ * parsers.eof / self.expandtabs
+ + parsers.spacechar^1 * parsers.Endline
+ / writer.soft_line_break
+ + parsers.spacechar^1
+ * -parsers.newline / self.expandtabs
+
+ parsers.NonbreakingEndline
+ = parsers.endline
+ / writer.nbsp
+
+ parsers.NonbreakingSpace
+ = parsers.spacechar^2 * parsers.endline
+ / writer.nbsp
+ + parsers.spacechar^1
+ * parsers.endline^-1 * parsers.eof / ""
+ + parsers.spacechar^1 * parsers.endline
+ * parsers.optionalspace
+ / writer.nbsp
+ + parsers.spacechar^1 * parsers.optionalspace
+ / writer.nbsp
+
+function self.auto_link_url(url, attributes)
+ return writer.link(writer.escape(url),
+ url, nil, attributes)
+end
+function self.auto_link_email(email, attributes)
+ return writer.link(writer.escape(email),
+ "mailto:"..email,
+ nil, attributes)
+end
+
+ parsers.AutoLinkUrl = parsers.auto_link_url
+ / self.auto_link_url
+
+ parsers.AutoLinkEmail
+ = parsers.auto_link_email
+ / self.auto_link_email
+
+ parsers.AutoLinkRelativeReference
+ = parsers.auto_link_relative_reference
+ / self.auto_link_url
+
+ parsers.LinkAndEmph = Ct(parsers.link_and_emph_table)
+ / self.defer_link_and_emphasis_processing
+
+ parsers.EscapedChar = parsers.backslash
+ * C(parsers.escapable) / writer.string
+
+ parsers.InlineHtml = Cs(parsers.html_inline_comment)
+ / writer.inline_html_comment
+ + Cs(parsers.html_any_empty_inline_tag
+ + parsers.html_inline_instruction
+ + parsers.html_inline_cdatasection
+ + parsers.html_inline_declaration
+ + parsers.html_any_open_inline_tag
+ + parsers.html_any_close_tag)
+ / writer.inline_html_tag
+
+ parsers.HtmlEntity = parsers.html_entities / writer.string
+ parsers.DisplayHtml = Cs(parsers.check_trail
+ * ( parsers.html_comment
+ + parsers.html_special_block
+ + parsers.html_block
+ + parsers.html_any_block
+ + parsers.html_instruction
+ + parsers.html_cdatasection
+ + parsers.html_declaration))
+ / writer.block_html_element
+
+ parsers.indented_non_blank_line = parsers.indentedline
+ - parsers.blankline
+
+ parsers.Verbatim
+ = Cs( parsers.check_code_trail
+ * (parsers.line - parsers.blankline)
+ * (( parsers.check_minimal_blank_indent_and_full_code_trail
+ * parsers.blankline)^0
+ * ( (parsers.check_minimal_indent / "")
+ * parsers.check_code_trail
+ * (parsers.line - parsers.blankline))^1)^0)
+ / self.expandtabs / writer.verbatim
+
+ parsers.Blockquote = parsers.blockquote_body
+ / writer.blockquote
+
+ parsers.ThematicBreak = parsers.thematic_break_lines
+ / writer.thematic_break
+
+ parsers.Reference = parsers.define_reference_parser
+ / self.register_link
+
+ parsers.Paragraph = parsers.freeze_trail
+ * (Ct((parsers.Inline)^1)
+ * (parsers.newline + parsers.eof)
+ * parsers.unfreeze_trail
+ / writer.paragraph)
+
+ parsers.Plain = parsers.nonindentspace * Ct(parsers.Inline^1)
+ / writer.plain
+
+ if options.taskLists then
+ parsers.tickbox = ( parsers.ticked_box
+ + parsers.halfticked_box
+ + parsers.unticked_box
+ ) / writer.tickbox
+ else
+ parsers.tickbox = parsers.fail
+ end
+
+ parsers.list_blank = parsers.conditionally_indented_blankline
+
+ parsers.ref_or_block_list_separated
+ = parsers.sep_group_no_output(parsers.list_blank)
+ * parsers.minimally_indented_ref
+ + parsers.block_sep_group(parsers.list_blank)
+ * parsers.minimally_indented_block
+
+ parsers.ref_or_block_non_separated
+ = parsers.minimally_indented_ref
+ + (parsers.succeed / writer.interblocksep)
+ * parsers.minimally_indented_block
+ - parsers.minimally_indented_blankline
+
+ parsers.tight_list_loop_body_pair =
+ parsers.create_loop_body_pair(
+ parsers.ref_or_block_non_separated,
+ parsers.minimally_indented_par_or_plain_no_blank,
+ (parsers.succeed / writer.interblocksep),
+ (parsers.succeed / writer.paragraphsep))
+
+ parsers.loose_list_loop_body_pair =
+ parsers.create_loop_body_pair(
+ parsers.ref_or_block_list_separated,
+ parsers.minimally_indented_par_or_plain,
+ parsers.block_sep_group(parsers.list_blank),
+ parsers.par_sep_group(parsers.list_blank))
+
+ parsers.tight_list_content_loop
+ = V("Block")
+ * parsers.tight_list_loop_body_pair.block^0
+ + (V("Paragraph") + V("Plain"))
+ * parsers.ref_or_block_non_separated
+ * parsers.tight_list_loop_body_pair.block^0
+ + (V("Paragraph") + V("Plain"))
+ * parsers.tight_list_loop_body_pair.par^0
+
+ parsers.loose_list_content_loop
+ = V("Block")
+ * parsers.loose_list_loop_body_pair.block^0
+ + (V("Paragraph") + V("Plain"))
+ * parsers.ref_or_block_list_separated
+ * parsers.loose_list_loop_body_pair.block^0
+ + (V("Paragraph") + V("Plain"))
+ * parsers.loose_list_loop_body_pair.par^0
+
+ parsers.list_item_tightness_condition
+ = -#( parsers.list_blank^0
+ * parsers.minimally_indented_ref_or_block_or_par)
+ * remove_indent("li")
+ + remove_indent("li")
+ * parsers.fail
+
+ parsers.indented_content_tight
+ = Ct( (parsers.blankline / "")
+ * #parsers.list_blank
+ * remove_indent("li")
+ + ( (V("Reference") + (parsers.blankline / ""))
+ * parsers.check_minimal_indent
+ * parsers.tight_list_content_loop
+ + (V("Reference") + (parsers.blankline / ""))
+ + (parsers.tickbox^-1 / writer.escape)
+ * parsers.tight_list_content_loop
+ )
+ * parsers.list_item_tightness_condition)
+
+ parsers.indented_content_loose
+ = Ct( (parsers.blankline / "")
+ * #parsers.list_blank
+ + ( (V("Reference") + (parsers.blankline / ""))
+ * parsers.check_minimal_indent
+ * parsers.loose_list_content_loop
+ + (V("Reference") + (parsers.blankline / ""))
+ + (parsers.tickbox^-1 / writer.escape)
+ * parsers.loose_list_content_loop))
+
+ parsers.TightListItem = function(starter)
+ return -parsers.ThematicBreak
+ * parsers.add_indent(starter, "li")
+ * parsers.indented_content_tight
+ end
+
+ parsers.LooseListItem = function(starter)
+ return -parsers.ThematicBreak
+ * parsers.add_indent(starter, "li")
+ * parsers.indented_content_loose
+ * remove_indent("li")
+ end
+
+ parsers.BulletListOfType = function(bullet_type)
+ local bullet = parsers.bullet(bullet_type)
+ return ( Ct( parsers.TightListItem(bullet)
+ * ( (parsers.check_minimal_indent / "")
+ * parsers.TightListItem(bullet)
+ )^0
+ )
+ * Cc(true)
+ * -#( (parsers.list_blank^0 / "")
+ * parsers.check_minimal_indent
+ * (bullet - parsers.ThematicBreak)
+ )
+ + Ct( parsers.LooseListItem(bullet)
+ * ( (parsers.list_blank^0 / "")
+ * (parsers.check_minimal_indent / "")
+ * parsers.LooseListItem(bullet)
+ )^0
+ )
+ * Cc(false)
+ ) / writer.bulletlist
+ end
+
+ parsers.BulletList = parsers.BulletListOfType(parsers.dash)
+ + parsers.BulletListOfType(parsers.asterisk)
+ + parsers.BulletListOfType(parsers.plus)
+
+ local function ordered_list(items,tight,starter)
+ local startnum = starter[2][1]
+ if options.startNumber then
+ startnum = tonumber(startnum) or 1 -- fallback for '#'
+ if startnum ~= nil then
+ startnum = math.floor(startnum)
+ end
+ else
+ startnum = nil
+ end
+ return writer.orderedlist(items,tight,startnum)
+ end
+
+ parsers.OrderedListOfType = function(delimiter_type)
+ local enumerator = parsers.enumerator(delimiter_type)
+ return Cg(enumerator, "listtype")
+ * (Ct( parsers.TightListItem(Cb("listtype"))
+ * ( (parsers.check_minimal_indent / "")
+ * parsers.TightListItem(enumerator))^0)
+ * Cc(true)
+ * -#((parsers.list_blank^0 / "")
+ * parsers.check_minimal_indent * enumerator)
+ + Ct( parsers.LooseListItem(Cb("listtype"))
+ * ((parsers.list_blank^0 / "")
+ * (parsers.check_minimal_indent / "")
+ * parsers.LooseListItem(enumerator))^0)
+ * Cc(false)
+ ) * Ct(Cb("listtype")) / ordered_list
+ end
+
+ parsers.OrderedList = parsers.OrderedListOfType(parsers.period)
+ + parsers.OrderedListOfType(parsers.rparent)
+ parsers.Blank = parsers.blankline / ""
+ + V("Reference")
+ function parsers.parse_heading_text(s)
+ local inlines = self.parser_functions.parse_inlines(s)
+ local flatten_inlines = self.writer.flatten_inlines
+ self.writer.flatten_inlines = true
+ local flat_text = self.parser_functions.parse_inlines(s)
+ flat_text = util.rope_to_string(flat_text)
+ self.writer.flatten_inlines = flatten_inlines
+ return {flat_text, inlines}
+ end
+
+ -- parse atx header
+ parsers.AtxHeading = parsers.check_trail_no_rem
+ * Cg(parsers.heading_start, "level")
+ * ((C( parsers.optionalspace
+ * parsers.hash^0
+ * parsers.optionalspace
+ * parsers.newline)
+ + parsers.spacechar^1
+ * C(parsers.line))
+ / strip_atx_end
+ / parsers.parse_heading_text)
+ * Cb("level")
+ / writer.heading
+
+ parsers.heading_line = parsers.linechar^1
+ - parsers.thematic_break_lines
+
+ parsers.heading_text = parsers.heading_line
+ * ( (V("Endline") / "\n")
+ * ( parsers.heading_line
+ - parsers.heading_level))^0
+ * parsers.newline^-1
+
+ parsers.SetextHeading = parsers.freeze_trail
+ * parsers.check_trail_no_rem
+ * #( parsers.heading_text
+ * parsers.check_minimal_indent
+ * parsers.check_trail
+ * parsers.heading_level)
+ * Cs(parsers.heading_text)
+ / parsers.parse_heading_text
+ * parsers.check_minimal_indent_and_trail
+ * parsers.heading_level
+ * parsers.newline
+ * parsers.unfreeze_trail
+ / writer.heading
+
+ parsers.Heading = parsers.AtxHeading + parsers.SetextHeading
+ function self.finalize_grammar(extensions)
+ local walkable_syntax = (function(global_walkable_syntax)
+ local local_walkable_syntax = {}
+ for lhs, rule in pairs(global_walkable_syntax) do
+ local_walkable_syntax[lhs] = util.table_copy(rule)
+ end
+ return local_walkable_syntax
+ end)(walkable_syntax)
+ local current_extension_name = nil
+ self.insert_pattern = function(selector, pattern, pattern_name)
+ assert(pattern_name == nil or type(pattern_name) == "string")
+ local _, _, lhs, pos, rhs
+ = selector:find("^(%a+)%s+([%a%s]+%a+)%s+(%a+)$")
+ assert(lhs ~= nil,
+ [[Expected selector in form ]]
+ .. [["LHS (before|after|instead of) RHS", not "]]
+ .. selector .. [["]])
+ assert(walkable_syntax[lhs] ~= nil,
+ [[Rule ]] .. lhs
+ .. [[ -> ... does not exist in markdown grammar]])
+ assert(pos == "before" or pos == "after" or pos == "instead of",
+ [[Expected positional specifier "before", "after", ]]
+ .. [[or "instead of", not "]]
+ .. pos .. [["]])
+ local rule = walkable_syntax[lhs]
+ local index = nil
+ for current_index, current_rhs in ipairs(rule) do
+ if type(current_rhs) == "string" and current_rhs == rhs then
+ index = current_index
+ if pos == "after" then
+ index = index + 1
+ end
+ break
+ end
+ end
+ assert(index ~= nil,
+ [[Rule ]] .. lhs .. [[ -> ]] .. rhs
+ .. [[ does not exist in markdown grammar]])
+ local accountable_pattern
+ if current_extension_name then
+ accountable_pattern
+ = {pattern, current_extension_name, pattern_name}
+ else
+ assert(type(pattern) == "string",
+ [[reader->insert_pattern() was called outside ]]
+ .. [[an extension with ]]
+ .. [[a PEG pattern instead of a rule name]])
+ accountable_pattern = pattern
+ end
+ if pos == "instead of" then
+ rule[index] = accountable_pattern
+ else
+ table.insert(rule, index, accountable_pattern)
+ end
+ end
+ local syntax =
+ { "Blocks",
+
+ Blocks = V("InitializeState")
+ * V("ExpectedJekyllData")
+ * V("Blank")^0
+ * ( V("Block")
+ * ( V("Blank")^0 * parsers.eof
+ + ( V("Blank")^2 / writer.paragraphsep
+ + V("Blank")^0 / writer.interblocksep
+ )
+ )
+ + ( V("Paragraph") + V("Plain") )
+ * ( V("Blank")^0 * parsers.eof
+ + ( V("Blank")^2 / writer.paragraphsep
+ + V("Blank")^0 / writer.interblocksep
+ )
+ )
+ * V("Block")
+ * ( V("Blank")^0 * parsers.eof
+ + ( V("Blank")^2 / writer.paragraphsep
+ + V("Blank")^0 / writer.interblocksep
+ )
+ )
+ + ( V("Paragraph") + V("Plain") )
+ * ( V("Blank")^0 * parsers.eof
+ + V("Blank")^0 / writer.paragraphsep
+ )
+ )^0,
+
+ ExpectedJekyllData = parsers.succeed,
+
+ Blank = parsers.Blank,
+ Reference = parsers.Reference,
+
+ Blockquote = parsers.Blockquote,
+ Verbatim = parsers.Verbatim,
+ ThematicBreak = parsers.ThematicBreak,
+ BulletList = parsers.BulletList,
+ OrderedList = parsers.OrderedList,
+ DisplayHtml = parsers.DisplayHtml,
+ Heading = parsers.Heading,
+ Paragraph = parsers.Paragraph,
+ Plain = parsers.Plain,
+
+ EndlineExceptions = parsers.EndlineExceptions,
+ NoSoftLineBreakEndlineExceptions
+ = parsers.NoSoftLineBreakEndlineExceptions,
+
+ Str = parsers.Str,
+ Space = parsers.Space,
+ NoSoftLineBreakSpace
+ = parsers.NoSoftLineBreakSpace,
+ OptionalIndent = parsers.OptionalIndent,
+ Endline = parsers.Endline,
+ EndlineNoSub = parsers.EndlineNoSub,
+ NoSoftLineBreakEndline
+ = parsers.NoSoftLineBreakEndline,
+ EndlineBreak = parsers.EndlineBreak,
+ LinkAndEmph = parsers.LinkAndEmph,
+ Code = parsers.Code,
+ AutoLinkUrl = parsers.AutoLinkUrl,
+ AutoLinkEmail = parsers.AutoLinkEmail,
+ AutoLinkRelativeReference
+ = parsers.AutoLinkRelativeReference,
+ InlineHtml = parsers.InlineHtml,
+ HtmlEntity = parsers.HtmlEntity,
+ EscapedChar = parsers.EscapedChar,
+ Smart = parsers.Smart,
+ Symbol = parsers.Symbol,
+ SpecialChar = parsers.fail,
+ InitializeState = parsers.succeed,
+ }
+ self.update_rule = function(rule_name, get_pattern)
+ assert(current_extension_name ~= nil)
+ assert(syntax[rule_name] ~= nil,
+ [[Rule ]] .. rule_name
+ .. [[ -> ... does not exist in markdown grammar]])
+ local previous_pattern
+ local extension_name
+ if walkable_syntax[rule_name] then
+ local previous_accountable_pattern
+ = walkable_syntax[rule_name][1]
+ previous_pattern = previous_accountable_pattern[1]
+ extension_name
+ = previous_accountable_pattern[2]
+ .. ", " .. current_extension_name
+ else
+ previous_pattern = nil
+ extension_name = current_extension_name
+ end
+ local pattern
+ if type(get_pattern) == "function" then
+ pattern = get_pattern(previous_pattern)
+ else
+ assert(previous_pattern == nil,
+ [[Rule ]] .. rule_name ..
+ [[ has already been updated by ]] .. extension_name)
+ pattern = get_pattern
+ end
+ local accountable_pattern = { pattern, extension_name, rule_name }
+ walkable_syntax[rule_name] = { accountable_pattern }
+ end
+ local special_characters = {}
+ self.add_special_character = function(c)
+ table.insert(special_characters, c)
+ syntax.SpecialChar = S(table.concat(special_characters, ""))
+ end
+
+ self.add_special_character("*")
+ self.add_special_character("[")
+ self.add_special_character("]")
+ self.add_special_character("<")
+ self.add_special_character("!")
+ self.add_special_character("\\")
+ self.initialize_named_group = function(name, value)
+ local pattern = Ct("")
+ if value ~= nil then
+ pattern = pattern / value
+ end
+ syntax.InitializeState = syntax.InitializeState
+ * Cg(pattern, name)
+ end
+ self.initialize_named_group("indent_info")
+ for _, extension in ipairs(extensions) do
+ current_extension_name = extension.name
+ extension.extend_writer(writer)
+ extension.extend_reader(self)
+ end
+ current_extension_name = nil
+ if options.debugExtensions then
+ local sorted_lhs = {}
+ for lhs, _ in pairs(walkable_syntax) do
+ table.insert(sorted_lhs, lhs)
+ end
+ table.sort(sorted_lhs)
+
+ local output_lines = {"{"}
+ for lhs_index, lhs in ipairs(sorted_lhs) do
+ local encoded_lhs = util.encode_json_string(lhs)
+ table.insert(output_lines, [[ ]] ..encoded_lhs .. [[: []])
+ local rule = walkable_syntax[lhs]
+ for rhs_index, rhs in ipairs(rule) do
+ local human_readable_rhs
+ if type(rhs) == "string" then
+ human_readable_rhs = rhs
+ else
+ local pattern_name
+ if rhs[3] then
+ pattern_name = rhs[3]
+ else
+ pattern_name = "Anonymous Pattern"
+ end
+ local extension_name = rhs[2]
+ human_readable_rhs = pattern_name .. [[ (]]
+ .. extension_name .. [[)]]
+ end
+ local encoded_rhs
+ = util.encode_json_string(human_readable_rhs)
+ local output_line = [[ ]] .. encoded_rhs
+ if rhs_index < #rule then
+ output_line = output_line .. ","
+ end
+ table.insert(output_lines, output_line)
+ end
+ local output_line = " ]"
+ if lhs_index < #sorted_lhs then
+ output_line = output_line .. ","
+ end
+ table.insert(output_lines, output_line)
+ end
+ table.insert(output_lines, "}")
+
+ local output = table.concat(output_lines, "\n")
+ local output_filename = options.debugExtensionsFileName
+ local output_file = assert(io.open(output_filename, "w"),
+ [[Could not open file "]] .. output_filename
+ .. [[" for writing]])
+ assert(output_file:write(output))
+ assert(output_file:close())
+ end
+ for lhs, rule in pairs(walkable_syntax) do
+ syntax[lhs] = parsers.fail
+ for _, rhs in ipairs(rule) do
+ local pattern
+ if type(rhs) == "string" then
+ pattern = V(rhs)
+ else
+ pattern = rhs[1]
+ if type(pattern) == "string" then
+ pattern = V(pattern)
+ end
+ end
+ syntax[lhs] = syntax[lhs] + pattern
+ end
+ end
+ if options.underscores then
+ self.add_special_character("_")
+ end
+
+ if not options.codeSpans then
+ syntax.Code = parsers.fail
+ else
+ self.add_special_character("`")
+ end
+
+ if not options.html then
+ syntax.DisplayHtml = parsers.fail
+ syntax.InlineHtml = parsers.fail
+ syntax.HtmlEntity = parsers.fail
+ else
+ self.add_special_character("&")
+ end
+
+ if options.preserveTabs then
+ options.stripIndent = false
+ end
+
+ if not options.smartEllipses then
+ syntax.Smart = parsers.fail
+ else
+ self.add_special_character(".")
+ end
+
+ if not options.relativeReferences then
+ syntax.AutoLinkRelativeReference = parsers.fail
+ end
+
+ if options.contentLevel == "inline" then
+ syntax[1] = "Inlines"
+ syntax.Inlines = V("InitializeState")
+ * parsers.Inline^0
+ * ( parsers.spacing^0
+ * parsers.eof / "")
+ syntax.Space = parsers.Space + parsers.blankline / writer.space
+ end
+
+ local blocks_nested_t = util.table_copy(syntax)
+ blocks_nested_t.ExpectedJekyllData = parsers.succeed
+ parsers.blocks_nested = Ct(blocks_nested_t)
+
+ parsers.blocks = Ct(syntax)
+
+ local inlines_t = util.table_copy(syntax)
+ inlines_t[1] = "Inlines"
+ inlines_t.Inlines = V("InitializeState")
+ * parsers.Inline^0
+ * ( parsers.spacing^0
+ * parsers.eof / "")
+ parsers.inlines = Ct(inlines_t)
+
+ local inlines_no_inline_note_t = util.table_copy(inlines_t)
+ inlines_no_inline_note_t.InlineNote = parsers.fail
+ parsers.inlines_no_inline_note = Ct(inlines_no_inline_note_t)
+
+ local inlines_no_html_t = util.table_copy(inlines_t)
+ inlines_no_html_t.DisplayHtml = parsers.fail
+ inlines_no_html_t.InlineHtml = parsers.fail
+ inlines_no_html_t.HtmlEntity = parsers.fail
+ parsers.inlines_no_html = Ct(inlines_no_html_t)
+
+ local inlines_nbsp_t = util.table_copy(inlines_t)
+ inlines_nbsp_t.Endline = parsers.NonbreakingEndline
+ inlines_nbsp_t.Space = parsers.NonbreakingSpace
+ parsers.inlines_nbsp = Ct(inlines_nbsp_t)
+
+ local inlines_no_link_or_emphasis_t = util.table_copy(inlines_t)
+ inlines_no_link_or_emphasis_t.LinkAndEmph = parsers.fail
+ inlines_no_link_or_emphasis_t.EndlineExceptions
+ = parsers.EndlineExceptions - parsers.eof
+ parsers.inlines_no_link_or_emphasis
+ = Ct(inlines_no_link_or_emphasis_t)
+ return function(input)
+ if options.unicodeNormalization then
+ local form = options.unicodeNormalizationForm
+ if form == "nfc" then
+ input = uni_algos.normalize.NFC(input)
+ elseif form == "nfd" then
+ input = uni_algos.normalize.NFD(input)
+ elseif form == "nfkc" then
+ input = uni_algos.normalize.NFKC(input)
+ elseif form == "nfkd" then
+ input = uni_algos.normalize.NFKD(input)
+ else
+ return writer.error(
+ format("Unknown normalization form %s", form))
+ end
+ end
+ input = input:gsub("\r\n?", "\n")
+ if input:sub(-1) ~= "\n" then
+ input = input .. "\n"
+ end
+ references = {}
+ local document = self.parser_functions.parse_blocks(input)
+ local output = util.rope_to_string(writer.document(document))
+ local undosep_start, undosep_end
+ local potential_secend_start, secend_start
+ local potential_sep_start, sep_start
+ while true do
+ -- find a `writer->undosep`
+ undosep_start, undosep_end
+ = output:find(writer.undosep_text, 1, true)
+ if undosep_start == nil then break end
+ -- skip any preceding section ends
+ secend_start = undosep_start
+ while true do
+ potential_secend_start = secend_start - #writer.secend_text
+ if potential_secend_start < 1
+ or output:sub(potential_secend_start,
+ secend_start - 1) ~= writer.secend_text
+ then
+ break
+ end
+ secend_start = potential_secend_start
+ end
+ -- find an immediately preceding
+ -- block element / paragraph separator
+ sep_start = secend_start
+ potential_sep_start = sep_start - #writer.interblocksep_text
+ if potential_sep_start >= 1
+ and output:sub(potential_sep_start,
+ sep_start - 1) == writer.interblocksep_text
+ then
+ sep_start = potential_sep_start
+ else
+ potential_sep_start = sep_start - #writer.paragraphsep_text
+ if potential_sep_start >= 1
+ and output:sub(potential_sep_start,
+ sep_start - 1) == writer.paragraphsep_text
+ then
+ sep_start = potential_sep_start
+ end
+ end
+ -- remove `writer->undosep` and immediately preceding
+ -- block element / paragraph separator
+ output = output:sub(1, sep_start - 1)
+ .. output:sub(secend_start, undosep_start - 1)
+ .. output:sub(undosep_end + 1)
+ end
+ return output
+ end
+ end
+ return self
+end
+M.extensions = {}
+M.extensions.bracketed_spans = function()
+ return {
+ name = "built-in bracketed_spans syntax extension",
+ extend_writer = function(self)
+ function self.span(s, attr)
+ if self.flatten_inlines then return s end
+ return {"\\markdownRendererBracketedSpanAttributeContextBegin",
+ self.attributes(attr),
+ s,
+ "\\markdownRendererBracketedSpanAttributeContextEnd{}"}
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
+
+ local span_label = parsers.lbracket
+ * (Cs((parsers.alphanumeric^1
+ + parsers.inticks
+ + parsers.autolink
+ + V("InlineHtml")
+ + ( parsers.backslash * parsers.backslash)
+ + ( parsers.backslash
+ * (parsers.lbracket + parsers.rbracket)
+ + V("Space") + V("Endline")
+ + (parsers.any
+ - ( parsers.newline
+ + parsers.lbracket
+ + parsers.rbracket
+ + parsers.blankline^2))))^1)
+ / self.parser_functions.parse_inlines)
+ * parsers.rbracket
+
+ local Span = span_label
+ * Ct(parsers.attributes)
+ / writer.span
+
+ self.insert_pattern("Inline before LinkAndEmph",
+ Span, "Span")
+ end
+ }
+end
+M.extensions.citations = function(citation_nbsps)
+ return {
+ name = "built-in citations syntax extension",
+ extend_writer = function(self)
+ function self.citations(text_cites, cites)
+ local buffer = {}
+ if self.flatten_inlines then
+ for _,cite in ipairs(cites) do
+ if cite.prenote then
+ table.insert(buffer, {cite.prenote, " "})
+ end
+ table.insert(buffer, cite.name)
+ if cite.postnote then
+ table.insert(buffer, {" ", cite.postnote})
+ end
+ end
+ else
+ table.insert(buffer,
+ {"\\markdownRenderer",
+ text_cites and "TextCite" or "Cite",
+ "{", #cites, "}"})
+ for _,cite in ipairs(cites) do
+ table.insert(buffer,
+ {cite.suppress_author and "-" or "+", "{",
+ cite.prenote or "", "}{",
+ cite.postnote or "", "}{", cite.name, "}"})
+ end
+ end
+ return buffer
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
+
+ local citation_chars
+ = parsers.alphanumeric
+ + S("#$%&-+<>~/_")
+
+ local citation_name
+ = Cs(parsers.dash^-1) * parsers.at
+ * Cs(citation_chars
+ * ((( citation_chars
+ + parsers.internal_punctuation
+ - parsers.comma - parsers.semicolon)
+ * -#(( parsers.internal_punctuation
+ - parsers.comma
+ - parsers.semicolon)^0
+ * -( citation_chars
+ + parsers.internal_punctuation
+ - parsers.comma
+ - parsers.semicolon)))^0
+ * citation_chars)^-1)
+
+ local citation_body_prenote
+ = Cs((parsers.alphanumeric^1
+ + parsers.bracketed
+ + parsers.inticks
+ + parsers.autolink
+ + V("InlineHtml")
+ + V("Space") + V("EndlineNoSub")
+ + (parsers.anyescaped
+ - ( parsers.newline
+ + parsers.rbracket
+ + parsers.blankline^2))
+ - ( parsers.spnl
+ * parsers.dash^-1
+ * parsers.at))^1)
+
+ local citation_body_postnote
+ = Cs((parsers.alphanumeric^1
+ + parsers.bracketed
+ + parsers.inticks
+ + parsers.autolink
+ + V("InlineHtml")
+ + V("Space") + V("EndlineNoSub")
+ + (parsers.anyescaped
+ - ( parsers.newline
+ + parsers.rbracket
+ + parsers.semicolon
+ + parsers.blankline^2))
+ - (parsers.spnl * parsers.rbracket))^1)
+
+ local citation_body_chunk
+ = ( citation_body_prenote
+ * parsers.spnlc_sep
+ + Cc("")
+ * parsers.spnlc
+ )
+ * citation_name
+ * ( parsers.internal_punctuation
+ - parsers.semicolon)^-1
+ * ( parsers.spnlc / function(_) return end
+ * citation_body_postnote
+ + Cc("")
+ * parsers.spnlc
+ )
+
+ local citation_body
+ = citation_body_chunk
+ * ( parsers.semicolon
+ * parsers.spnlc
+ * citation_body_chunk
+ )^0
+
+ local citation_headless_body_postnote
+ = Cs((parsers.alphanumeric^1
+ + parsers.bracketed
+ + parsers.inticks
+ + parsers.autolink
+ + V("InlineHtml")
+ + V("Space") + V("Endline")
+ + (parsers.anyescaped
+ - ( parsers.newline
+ + parsers.rbracket
+ + parsers.at
+ + parsers.semicolon + parsers.blankline^2))
+ - (parsers.spnl * parsers.rbracket))^0)
+
+ local citation_headless_body
+ = citation_headless_body_postnote
+ * ( parsers.semicolon
+ * parsers.spnlc
+ * citation_body_chunk
+ )^0
+
+ local citations
+ = function(text_cites, raw_cites)
+ local function normalize(str)
+ if str == "" then
+ str = nil
+ else
+ str = (citation_nbsps and
+ self.parser_functions.parse_inlines_nbsp or
+ self.parser_functions.parse_inlines)(str)
+ end
+ return str
+ end
+
+ local cites = {}
+ for i = 1,#raw_cites,4 do
+ cites[#cites+1] = {
+ prenote = normalize(raw_cites[i]),
+ suppress_author = raw_cites[i+1] == "-",
+ name = writer.identifier(raw_cites[i+2]),
+ postnote = normalize(raw_cites[i+3]),
+ }
+ end
+ return writer.citations(text_cites, cites)
+ end
+
+ local TextCitations
+ = Ct((parsers.spnlc
+ * Cc("")
+ * citation_name
+ * ((parsers.spnlc
+ * parsers.lbracket
+ * citation_headless_body
+ * parsers.rbracket) + Cc("")))^1)
+ / function(raw_cites)
+ return citations(true, raw_cites)
+ end
+
+ local ParenthesizedCitations
+ = Ct((parsers.spnlc
+ * parsers.lbracket
+ * citation_body
+ * parsers.rbracket)^1)
+ / function(raw_cites)
+ return citations(false, raw_cites)
+ end
+
+ local Citations = TextCitations + ParenthesizedCitations
+
+ self.insert_pattern("Inline before LinkAndEmph",
+ Citations, "Citations")
+
+ self.add_special_character("@")
+ self.add_special_character("-")
+ end
+ }
+end
+M.extensions.content_blocks = function(language_map)
+ local languages_json = (function()
+ local base, prev, curr
+ for _, pathname in ipairs{kpse.lookup(language_map,
+ {all=true})} do
+ local file = io.open(pathname, "r")
+ if not file then goto continue end
+ local input = assert(file:read("*a"))
+ assert(file:close())
+ local json = input:gsub('("[^\n]-"):','[%1]=')
+ curr = load("_ENV = {}; return "..json)()
+ if type(curr) == "table" then
+ if base == nil then
+ base = curr
+ else
+ setmetatable(prev, { __index = curr })
+ end
+ prev = curr
+ end
+ ::continue::
+ end
+ return base or {}
+ end)()
+
+ return {
+ name = "built-in content_blocks syntax extension",
+ extend_writer = function(self)
+ function self.contentblock(src,suf,type,tit)
+ if not self.is_writing then return "" end
+ src = src.."."..suf
+ suf = suf:lower()
+ if type == "onlineimage" then
+ return {"\\markdownRendererContentBlockOnlineImage{",suf,"}",
+ "{",self.string(src),"}",
+ "{",self.uri(src),"}",
+ "{",self.string(tit or ""),"}"}
+ elseif languages_json[suf] then
+ return {"\\markdownRendererContentBlockCode{",suf,"}",
+ "{",self.string(languages_json[suf]),"}",
+ "{",self.string(src),"}",
+ "{",self.uri(src),"}",
+ "{",self.string(tit or ""),"}"}
+ else
+ return {"\\markdownRendererContentBlock{",suf,"}",
+ "{",self.string(src),"}",
+ "{",self.uri(src),"}",
+ "{",self.string(tit or ""),"}"}
+ end
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
+
+ local contentblock_tail
+ = parsers.optionaltitle
+ * (parsers.newline + parsers.eof)
+
+ -- case insensitive online image suffix:
+ local onlineimagesuffix
+ = (function(...)
+ local parser = nil
+ for _, suffix in ipairs({...}) do
+ local pattern=nil
+ for i=1,#suffix do
+ local char=suffix:sub(i,i)
+ char = S(char:lower()..char:upper())
+ if pattern == nil then
+ pattern = char
+ else
+ pattern = pattern * char
+ end
+ end
+ if parser == nil then
+ parser = pattern
+ else
+ parser = parser + pattern
+ end
+ end
+ return parser
+ end)("png", "jpg", "jpeg", "gif", "tif", "tiff")
+
+ -- online image url for iA Writer content blocks with
+ -- mandatory suffix, allowing nested brackets:
+ local onlineimageurl
+ = (parsers.less
+ * Cs((parsers.anyescaped
+ - parsers.more
+ - parsers.spacing
+ - #(parsers.period
+ * onlineimagesuffix
+ * parsers.more
+ * contentblock_tail))^0)
+ * parsers.period
+ * Cs(onlineimagesuffix)
+ * parsers.more
+ + (Cs((parsers.inparens
+ + (parsers.anyescaped
+ - parsers.spacing
+ - parsers.rparent
+ - #(parsers.period
+ * onlineimagesuffix
+ * contentblock_tail)))^0)
+ * parsers.period
+ * Cs(onlineimagesuffix))
+ ) * Cc("onlineimage")
+
+ -- filename for iA Writer content blocks with mandatory suffix:
+ local localfilepath
+ = parsers.slash
+ * Cs((parsers.anyescaped
+ - parsers.tab
+ - parsers.newline
+ - #(parsers.period
+ * parsers.alphanumeric^1
+ * contentblock_tail))^1)
+ * parsers.period
+ * Cs(parsers.alphanumeric^1)
+ * Cc("localfile")
+
+ local ContentBlock
+ = parsers.check_trail_no_rem
+ * (localfilepath + onlineimageurl)
+ * contentblock_tail
+ / writer.contentblock
+
+ self.insert_pattern("Block before Blockquote",
+ ContentBlock, "ContentBlock")
+ end
+ }
+end
+M.extensions.definition_lists = function(tight_lists)
+ return {
+ name = "built-in definition_lists syntax extension",
+ extend_writer = function(self)
+ local function dlitem(term, defs)
+ local retVal = {"\\markdownRendererDlItem{",term,"}"}
+ for _, def in ipairs(defs) do
+ retVal[#retVal+1]
+ = {"\\markdownRendererDlDefinitionBegin ",def,
+ "\\markdownRendererDlDefinitionEnd "}
+ end
+ retVal[#retVal+1] = "\\markdownRendererDlItemEnd "
+ return retVal
+ end
+
+ function self.definitionlist(items,tight)
+ if not self.is_writing then return "" end
+ local buffer = {}
+ for _,item in ipairs(items) do
+ buffer[#buffer + 1] = dlitem(item.term, item.definitions)
+ end
+ if tight and tight_lists then
+ return {"\\markdownRendererDlBeginTight\n", buffer,
+ "\n\\markdownRendererDlEndTight"}
+ else
+ return {"\\markdownRendererDlBegin\n", buffer,
+ "\n\\markdownRendererDlEnd"}
+ end
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
+
+ local defstartchar = S("~:")
+
+ local defstart
+ = parsers.check_trail_length(0) * defstartchar
+ * #parsers.spacing
+ * (parsers.tab + parsers.space^-3)
+ + parsers.check_trail_length(1)
+ * defstartchar * #parsers.spacing
+ * (parsers.tab + parsers.space^-2)
+ + parsers.check_trail_length(2)
+ * defstartchar * #parsers.spacing
+ * (parsers.tab + parsers.space^-1)
+ + parsers.check_trail_length(3)
+ * defstartchar * #parsers.spacing
+
+ local indented_line
+ = (parsers.check_minimal_indent / "")
+ * parsers.check_code_trail * parsers.line
+
+ local blank
+ = parsers.check_minimal_blank_indent_and_any_trail
+ * parsers.optionalspace * parsers.newline
+
+ local dlchunk = Cs(parsers.line * (indented_line - blank)^0)
+
+ local indented_blocks = function(bl)
+ return Cs( bl
+ * (blank^1 * (parsers.check_minimal_indent / "")
+ * parsers.check_code_trail * -parsers.blankline * bl)^0
+ * (blank^1 + parsers.eof))
+ end
+
+ local function definition_list_item(term, defs, _)
+ return { term = self.parser_functions.parse_inlines(term),
+ definitions = defs }
+ end
+
+ local DefinitionListItemLoose
+ = C(parsers.line) * blank^0
+ * Ct((parsers.check_minimal_indent * (defstart
+ * indented_blocks(dlchunk)
+ / self.parser_functions.parse_blocks_nested))^1)
+ * Cc(false) / definition_list_item
+
+ local DefinitionListItemTight
+ = C(parsers.line)
+ * Ct((parsers.check_minimal_indent * (defstart * dlchunk
+ / self.parser_functions.parse_blocks_nested))^1)
+ * Cc(true) / definition_list_item
+
+ local DefinitionList
+ = ( Ct(DefinitionListItemLoose^1) * Cc(false)
+ + Ct(DefinitionListItemTight^1)
+ * (blank^0
+ * -DefinitionListItemLoose * Cc(true))
+ ) / writer.definitionlist
+
+ self.insert_pattern("Block after Heading",
+ DefinitionList, "DefinitionList")
+ end
+ }
+end
+M.extensions.fancy_lists = function()
+ return {
+ name = "built-in fancy_lists syntax extension",
+ extend_writer = function(self)
+ local options = self.options
+
+ function self.fancylist(items,tight,startnum,numstyle,numdelim)
+ if not self.is_writing then return "" end
+ local buffer = {}
+ local num = startnum
+ for _,item in ipairs(items) do
+ if item ~= "" then
+ buffer[#buffer + 1] = self.fancyitem(item,num)
+ end
+ if num ~= nil and item ~= "" then
+ num = num + 1
+ end
+ end
+ local contents = util.intersperse(buffer,"\n")
+ if tight and options.tightLists then
+ return {"\\markdownRendererFancyOlBeginTight{",
+ numstyle,"}{",numdelim,"}",contents,
+ "\n\\markdownRendererFancyOlEndTight "}
+ else
+ return {"\\markdownRendererFancyOlBegin{",
+ numstyle,"}{",numdelim,"}",contents,
+ "\n\\markdownRendererFancyOlEnd "}
+ end
+ end
+ function self.fancyitem(s,num)
+ if num ~= nil then
+ return {"\\markdownRendererFancyOlItemWithNumber{",num,"}",s,
+ "\\markdownRendererFancyOlItemEnd "}
+ else
+ return {"\\markdownRendererFancyOlItem ",s,
+ "\\markdownRendererFancyOlItemEnd "}
+ end
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local options = self.options
+ local writer = self.writer
+
+ local function combine_markers_and_delims(markers, delims)
+ local markers_table = {}
+ for _,marker in ipairs(markers) do
+ local start_marker
+ local continuation_marker
+ if type(marker) == "table" then
+ start_marker = marker[1]
+ continuation_marker = marker[2]
+ else
+ start_marker = marker
+ continuation_marker = marker
+ end
+ for _,delim in ipairs(delims) do
+ table.insert(markers_table,
+ {start_marker, continuation_marker, delim})
+ end
+ end
+ return markers_table
+ end
+
+ local function join_table_with_func(func, markers_table)
+ local pattern = func(table.unpack(markers_table[1]))
+ for i = 2, #markers_table do
+ pattern = pattern + func(table.unpack(markers_table[i]))
+ end
+ return pattern
+ end
+
+ local lowercase_letter_marker = R("az")
+ local uppercase_letter_marker = R("AZ")
+
+ local roman_marker = function(chars)
+ local m, d, c = P(chars[1]), P(chars[2]), P(chars[3])
+ local l, x, v, i
+ = P(chars[4]), P(chars[5]), P(chars[6]), P(chars[7])
+ return m^-3
+ * (c*m + c*d + d^-1 * c^-3)
+ * (x*c + x*l + l^-1 * x^-3)
+ * (i*x + i*v + v^-1 * i^-3)
+ end
+
+ local lowercase_roman_marker
+ = roman_marker({"m", "d", "c", "l", "x", "v", "i"})
+ local uppercase_roman_marker
+ = roman_marker({"M", "D", "C", "L", "X", "V", "I"})
+
+ local lowercase_opening_roman_marker = P("i")
+ local uppercase_opening_roman_marker = P("I")
+
+ local digit_marker = parsers.dig * parsers.dig^-8
+
+ local markers = {
+ {lowercase_opening_roman_marker, lowercase_roman_marker},
+ {uppercase_opening_roman_marker, uppercase_roman_marker},
+ lowercase_letter_marker,
+ uppercase_letter_marker,
+ lowercase_roman_marker,
+ uppercase_roman_marker,
+ digit_marker
+ }
+
+ local delims = {
+ parsers.period,
+ parsers.rparent
+ }
+
+ local markers_table = combine_markers_and_delims(markers, delims)
+
+ local function enumerator(start_marker, _,
+ delimiter_type, interrupting)
+ local delimiter_range
+ local allowed_end
+ if interrupting then
+ delimiter_range = P("1")
+ allowed_end = C(parsers.spacechar^1) * #parsers.linechar
+ else
+ delimiter_range = start_marker
+ allowed_end = C(parsers.spacechar^1)
+ + #(parsers.newline + parsers.eof)
+ end
+
+ return parsers.check_trail
+ * Ct(C(delimiter_range) * C(delimiter_type))
+ * allowed_end
+ end
+
+ local starter = join_table_with_func(enumerator, markers_table)
+
+ local TightListItem = function(starter)
+ return parsers.add_indent(starter, "li")
+ * parsers.indented_content_tight
+ end
+
+ local LooseListItem = function(starter)
+ return parsers.add_indent(starter, "li")
+ * parsers.indented_content_loose
+ * remove_indent("li")
+ end
+
+ local function roman2number(roman)
+ local romans = { ["M"] = 1000, ["D"] = 500, ["C"] = 100,
+ ["L"] = 50, ["X"] = 10, ["V"] = 5, ["I"] = 1 }
+ local numeral = 0
+
+ local i = 1
+ local len = string.len(roman)
+ while i < len do
+ local z1, z2 = romans[ string.sub(roman, i, i) ],
+ romans[ string.sub(roman, i+1, i+1) ]
+ if z1 < z2 then
+ numeral = numeral + (z2 - z1)
+ i = i + 2
+ else
+ numeral = numeral + z1
+ i = i + 1
+ end
+ end
+ if i <= len then
+ numeral = numeral + romans[ string.sub(roman,i,i) ]
+ end
+ return numeral
+ end
+
+ local function sniffstyle(numstr, delimend)
+ local numdelim
+ if delimend == ")" then
+ numdelim = "OneParen"
+ elseif delimend == "." then
+ numdelim = "Period"
+ else
+ numdelim = "Default"
+ end
+
+ local num
+ num = numstr:match("^([I])$")
+ if num then
+ return roman2number(num), "UpperRoman", numdelim
+ end
+ num = numstr:match("^([i])$")
+ if num then
+ return roman2number(string.upper(num)), "LowerRoman", numdelim
+ end
+ num = numstr:match("^([A-Z])$")
+ if num then
+ return string.byte(num) - string.byte("A") + 1,
+ "UpperAlpha", numdelim
+ end
+ num = numstr:match("^([a-z])$")
+ if num then
+ return string.byte(num) - string.byte("a") + 1,
+ "LowerAlpha", numdelim
+ end
+ num = numstr:match("^([IVXLCDM]+)")
+ if num then
+ return roman2number(num), "UpperRoman", numdelim
+ end
+ num = numstr:match("^([ivxlcdm]+)")
+ if num then
+ return roman2number(string.upper(num)), "LowerRoman", numdelim
+ end
+ return math.floor(tonumber(numstr) or 1), "Decimal", numdelim
+ end
+
+ local function fancylist(items,tight,start)
+ local startnum, numstyle, numdelim
+ = sniffstyle(start[2][1], start[2][2])
+ return writer.fancylist(items,tight,
+ options.startNumber and startnum or 1,
+ numstyle or "Decimal",
+ numdelim or "Default")
+ end
+
+ local FancyListOfType
+ = function(start_marker, continuation_marker, delimiter_type)
+ local enumerator_start
+ = enumerator(start_marker, continuation_marker,
+ delimiter_type)
+ local enumerator_cont
+ = enumerator(continuation_marker, continuation_marker,
+ delimiter_type)
+ return Cg(enumerator_start, "listtype")
+ * (Ct( TightListItem(Cb("listtype"))
+ * ((parsers.check_minimal_indent / "")
+ * TightListItem(enumerator_cont))^0)
+ * Cc(true)
+ * -#((parsers.conditionally_indented_blankline^0 / "")
+ * parsers.check_minimal_indent * enumerator_cont)
+ + Ct( LooseListItem(Cb("listtype"))
+ * ((parsers.conditionally_indented_blankline^0 / "")
+ * (parsers.check_minimal_indent / "")
+ * LooseListItem(enumerator_cont))^0)
+ * Cc(false)
+ ) * Ct(Cb("listtype")) / fancylist
+ end
+
+ local FancyList
+ = join_table_with_func(FancyListOfType, markers_table)
+
+ local Endline = parsers.newline
+ * (parsers.check_minimal_indent
+ * -parsers.EndlineExceptions
+ + parsers.check_optional_indent
+ * -parsers.EndlineExceptions
+ * -starter)
+ * parsers.spacechar^0
+ / writer.soft_line_break
+
+ self.update_rule("OrderedList", FancyList)
+ self.update_rule("Endline", Endline)
+ end
+ }
+end
+M.extensions.fenced_code = function(blank_before_code_fence,
+ allow_attributes,
+ allow_raw_blocks)
+ return {
+ name = "built-in fenced_code syntax extension",
+ extend_writer = function(self)
+ local options = self.options
+
+ function self.fencedCode(s, i, attr)
+ if not self.is_writing then return "" end
+ s = s:gsub("\n$", "")
+ local buf = {}
+ if attr ~= nil then
+ table.insert(buf,
+ {"\\markdownRendererFencedCodeAttributeContextBegin",
+ self.attributes(attr)})
+ end
+ local name = util.cache_verbatim(options.cacheDir, s)
+ table.insert(buf,
+ {"\\markdownRendererInputFencedCode{",
+ name,"}{",self.string(i),"}{",self.infostring(i),"}"})
+ if attr ~= nil then
+ table.insert(buf,
+ "\\markdownRendererFencedCodeAttributeContextEnd{}")
+ end
+ return buf
+ end
+
+ if allow_raw_blocks then
+ function self.rawBlock(s, attr)
+ if not self.is_writing then return "" end
+ s = s:gsub("\n$", "")
+ local name = util.cache_verbatim(options.cacheDir, s)
+ return {"\\markdownRendererInputRawBlock{",
+ name,"}{", self.string(attr),"}"}
+ end
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
+
+ local function captures_geq_length(_,i,a,b)
+ return #a >= #b and i
+ end
+
+ local function strip_enclosing_whitespaces(str)
+ return str:gsub("^%s*(.-)%s*$", "%1")
+ end
+
+ local tilde_infostring = Cs(Cs((V("HtmlEntity")
+ + parsers.anyescaped
+ - parsers.newline)^0)
+ / strip_enclosing_whitespaces)
+
+ local backtick_infostring
+ = Cs( Cs((V("HtmlEntity")
+ + ( -#(parsers.backslash * parsers.backtick)
+ * parsers.anyescaped)
+ - parsers.newline
+ - parsers.backtick)^0)
+ / strip_enclosing_whitespaces)
+
+ local fenceindent
+
+ local function has_trail(indent_table)
+ return indent_table ~= nil and
+ indent_table.trail ~= nil and
+ next(indent_table.trail) ~= nil
+ end
+
+ local function has_indents(indent_table)
+ return indent_table ~= nil and
+ indent_table.indents ~= nil and
+ next(indent_table.indents) ~= nil
+ end
+
+ local function get_last_indent_name(indent_table)
+ if has_indents(indent_table) then
+ return indent_table.indents[#indent_table.indents].name
+ end
+ end
+
+ local count_fenced_start_indent =
+ function(_, _, indent_table, trail)
+ local last_indent_name = get_last_indent_name(indent_table)
+ fenceindent = 0
+ if last_indent_name ~= "li" then
+ fenceindent = #trail
+ end
+ return true
+ end
+
+ local fencehead = function(char, infostring)
+ return Cmt( Cb("indent_info")
+ * parsers.check_trail, count_fenced_start_indent)
+ * Cg(char^3, "fencelength")
+ * parsers.optionalspace
+ * infostring
+ * (parsers.newline + parsers.eof)
+ end
+
+ local fencetail = function(char)
+ return parsers.check_trail_no_rem
+ * Cmt(C(char^3) * Cb("fencelength"), captures_geq_length)
+ * parsers.optionalspace * (parsers.newline + parsers.eof)
+ + parsers.eof
+ end
+
+ local process_fenced_line =
+ function(s, i, -- luacheck: ignore s i
+ indent_table, line_content, is_blank)
+ local remainder = ""
+ if has_trail(indent_table) then
+ remainder = indent_table.trail.internal_remainder
+ end
+
+ if is_blank
+ and get_last_indent_name(indent_table) == "li" then
+ remainder = ""
+ end
+
+ local str = remainder .. line_content
+ local index = 1
+ local remaining = fenceindent
+
+ while true do
+ local c = str:sub(index, index)
+ if c == " " and remaining > 0 then
+ remaining = remaining - 1
+ index = index + 1
+ elseif c == "\t" and remaining > 3 then
+ remaining = remaining - 4
+ index = index + 1
+ else
+ break
+ end
+ end
+
+ return true, str:sub(index)
+ end
+
+ local fencedline = function(char)
+ return Cmt( Cb("indent_info")
+ * C(parsers.line - fencetail(char))
+ * Cc(false), process_fenced_line)
+ end
+
+ local blankfencedline
+ = Cmt( Cb("indent_info")
+ * C(parsers.blankline)
+ * Cc(true), process_fenced_line)
+
+ local TildeFencedCode
+ = fencehead(parsers.tilde, tilde_infostring)
+ * Cs(( (parsers.check_minimal_blank_indent / "")
+ * blankfencedline
+ + ( parsers.check_minimal_indent / "")
+ * fencedline(parsers.tilde))^0)
+ * ( (parsers.check_minimal_indent / "")
+ * fencetail(parsers.tilde) + parsers.succeed)
+
+ local BacktickFencedCode
+ = fencehead(parsers.backtick, backtick_infostring)
+ * Cs(( (parsers.check_minimal_blank_indent / "")
+ * blankfencedline
+ + (parsers.check_minimal_indent / "")
+ * fencedline(parsers.backtick))^0)
+ * ( (parsers.check_minimal_indent / "")
+ * fencetail(parsers.backtick) + parsers.succeed)
+
+ local infostring_with_attributes
+ = Ct(C((parsers.linechar
+ - ( parsers.optionalspace
+ * parsers.attributes))^0)
+ * parsers.optionalspace
+ * Ct(parsers.attributes))
+
+ local FencedCode
+ = ((TildeFencedCode + BacktickFencedCode)
+ / function(infostring, code)
+ local expanded_code = self.expandtabs(code)
+
+ if allow_raw_blocks then
+ local raw_attr = lpeg.match(parsers.raw_attribute,
+ infostring)
+ if raw_attr then
+ return writer.rawBlock(expanded_code, raw_attr)
+ end
+ end
+
+ local attr = nil
+ if allow_attributes then
+ local match = lpeg.match(infostring_with_attributes,
+ infostring)
+ if match then
+ infostring, attr = table.unpack(match)
+ end
+ end
+ return writer.fencedCode(expanded_code, infostring, attr)
+ end)
+
+ self.insert_pattern("Block after Verbatim",
+ FencedCode, "FencedCode")
+
+ local fencestart
+ if blank_before_code_fence then
+ fencestart = parsers.fail
+ else
+ fencestart = fencehead(parsers.backtick, backtick_infostring)
+ + fencehead(parsers.tilde, tilde_infostring)
+ end
+
+ self.update_rule("EndlineExceptions", function(previous_pattern)
+ if previous_pattern == nil then
+ previous_pattern = parsers.EndlineExceptions
+ end
+ return previous_pattern + fencestart
+ end)
+
+ self.add_special_character("`")
+ self.add_special_character("~")
+ end
+ }
+end
+M.extensions.fenced_divs = function(blank_before_div_fence)
+ return {
+ name = "built-in fenced_divs syntax extension",
+ extend_writer = function(self)
+ function self.div_begin(attributes)
+ local start_output
+ = {"\\markdownRendererFencedDivAttributeContextBegin\n",
+ self.attributes(attributes)}
+ local end_output
+ = {"\\markdownRendererFencedDivAttributeContextEnd{}"}
+ return self.push_attributes(
+ "div", attributes, start_output, end_output)
+ end
+ function self.div_end()
+ return self.pop_attributes("div")
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
+ local fenced_div_infostring
+ = C((parsers.linechar
+ - ( parsers.spacechar^1
+ * parsers.colon^1))^1)
+
+ local fenced_div_begin = parsers.nonindentspace
+ * parsers.colon^3
+ * parsers.optionalspace
+ * fenced_div_infostring
+ * ( parsers.spacechar^1
+ * parsers.colon^1)^0
+ * parsers.optionalspace
+ * (parsers.newline + parsers.eof)
+
+ local fenced_div_end = parsers.nonindentspace
+ * parsers.colon^3
+ * parsers.optionalspace
+ * (parsers.newline + parsers.eof)
+ self.initialize_named_group("fenced_div_level", "0")
+ self.initialize_named_group("fenced_div_num_opening_indents")
+
+ local function increment_div_level()
+ local push_indent_table =
+ function(s, i, indent_table, -- luacheck: ignore s i
+ fenced_div_num_opening_indents, fenced_div_level)
+ fenced_div_level = tonumber(fenced_div_level) + 1
+ local num_opening_indents = 0
+ if indent_table.indents ~= nil then
+ num_opening_indents = #indent_table.indents
+ end
+ fenced_div_num_opening_indents[fenced_div_level]
+ = num_opening_indents
+ return true, fenced_div_num_opening_indents
+ end
+
+ local increment_level =
+ function(s, i, fenced_div_level) -- luacheck: ignore s i
+ fenced_div_level = tonumber(fenced_div_level) + 1
+ return true, tostring(fenced_div_level)
+ end
+
+ return Cg( Cmt( Cb("indent_info")
+ * Cb("fenced_div_num_opening_indents")
+ * Cb("fenced_div_level"), push_indent_table)
+ , "fenced_div_num_opening_indents")
+ * Cg( Cmt( Cb("fenced_div_level"), increment_level)
+ , "fenced_div_level")
+ end
+
+ local function decrement_div_level()
+ local pop_indent_table =
+ function(s, i, -- luacheck: ignore s i
+ fenced_div_indent_table, fenced_div_level)
+ fenced_div_level = tonumber(fenced_div_level)
+ fenced_div_indent_table[fenced_div_level] = nil
+ return true, tostring(fenced_div_level - 1)
+ end
+
+ return Cg( Cmt( Cb("fenced_div_num_opening_indents")
+ * Cb("fenced_div_level"), pop_indent_table)
+ , "fenced_div_level")
+ end
+
+ local non_fenced_div_block
+ = parsers.check_minimal_indent * V("Block")
+ - parsers.check_minimal_indent_and_trail * fenced_div_end
+
+ local non_fenced_div_paragraph
+ = parsers.check_minimal_indent * V("Paragraph")
+ - parsers.check_minimal_indent_and_trail * fenced_div_end
+
+ local blank = parsers.minimally_indented_blank
+
+ local block_separated = parsers.block_sep_group(blank)
+ * non_fenced_div_block
+
+ local loop_body_pair
+ = parsers.create_loop_body_pair(block_separated,
+ non_fenced_div_paragraph,
+ parsers.block_sep_group(blank),
+ parsers.par_sep_group(blank))
+
+ local content_loop = ( non_fenced_div_block
+ * loop_body_pair.block^0
+ + non_fenced_div_paragraph
+ * block_separated
+ * loop_body_pair.block^0
+ + non_fenced_div_paragraph
+ * loop_body_pair.par^0)
+ * blank^0
+
+ local FencedDiv = fenced_div_begin
+ / function (infostring)
+ local attr
+ = lpeg.match(Ct(parsers.attributes),
+ infostring)
+ if attr == nil then
+ attr = {"." .. infostring}
+ end
+ return attr
+ end
+ / writer.div_begin
+ * increment_div_level()
+ * parsers.skipblanklines
+ * Ct(content_loop)
+ * parsers.minimally_indented_blank^0
+ * parsers.check_minimal_indent_and_trail
+ * fenced_div_end
+ * decrement_div_level()
+ * (Cc("") / writer.div_end)
+
+ self.insert_pattern("Block after Verbatim",
+ FencedDiv, "FencedDiv")
+
+ self.add_special_character(":")
+
+ local function is_inside_div()
+ local check_div_level =
+ function(s, i, fenced_div_level) -- luacheck: ignore s i
+ fenced_div_level = tonumber(fenced_div_level)
+ return fenced_div_level > 0
+ end
+
+ return Cmt(Cb("fenced_div_level"), check_div_level)
+ end
+
+ local function check_indent()
+ local compare_indent =
+ function(s, i, indent_table, -- luacheck: ignore s i
+ fenced_div_num_opening_indents, fenced_div_level)
+ fenced_div_level = tonumber(fenced_div_level)
+ local num_current_indents
+ = ( indent_table.current_line_indents ~= nil and
+ #indent_table.current_line_indents) or 0
+ local num_opening_indents
+ = fenced_div_num_opening_indents[fenced_div_level]
+ return num_current_indents == num_opening_indents
+ end
+
+ return Cmt( Cb("indent_info")
+ * Cb("fenced_div_num_opening_indents")
+ * Cb("fenced_div_level"), compare_indent)
+ end
+
+ local fencestart = is_inside_div()
+ * fenced_div_end
+ * check_indent()
+
+ if not blank_before_div_fence then
+ self.update_rule("EndlineExceptions", function(previous_pattern)
+ if previous_pattern == nil then
+ previous_pattern = parsers.EndlineExceptions
+ end
+ return previous_pattern + fencestart
+ end)
+ end
+ end
+ }
+end
+M.extensions.header_attributes = function()
+ return {
+ name = "built-in header_attributes syntax extension",
+ extend_writer = function()
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
+
+ local function strip_atx_end(s)
+ return s:gsub("%s+#*%s*$","")
+ end
+
+ local AtxHeading = Cg(parsers.heading_start, "level")
+ * parsers.optionalspace
+ * (C(((parsers.linechar
+ - (parsers.attributes
+ * parsers.optionalspace
+ * parsers.newline))
+ * (parsers.linechar
+ - parsers.lbrace)^0)^1)
+ / strip_atx_end
+ / parsers.parse_heading_text)
+ * Cg(Ct(parsers.newline
+ + (parsers.attributes
+ * parsers.optionalspace
+ * parsers.newline)), "attributes")
+ * Cb("level")
+ * Cb("attributes")
+ / writer.heading
+
+ local function strip_trailing_spaces(s)
+ return s:gsub("%s*$","")
+ end
+
+ local heading_line = (parsers.linechar
+ - (parsers.attributes
+ * parsers.optionalspace
+ * parsers.newline))^1
+ - parsers.thematic_break_lines
+
+ local heading_text
+ = heading_line
+ * ( (V("Endline") / "\n")
+ * (heading_line - parsers.heading_level))^0
+ * parsers.newline^-1
+
+ local SetextHeading
+ = parsers.freeze_trail * parsers.check_trail_no_rem
+ * #(heading_text
+ * (parsers.attributes
+ * parsers.optionalspace
+ * parsers.newline)^-1
+ * parsers.check_minimal_indent
+ * parsers.check_trail
+ * parsers.heading_level)
+ * Cs(heading_text) / strip_trailing_spaces
+ / parsers.parse_heading_text
+ * Cg(Ct((parsers.attributes
+ * parsers.optionalspace
+ * parsers.newline)^-1), "attributes")
+ * parsers.check_minimal_indent_and_trail * parsers.heading_level
+ * Cb("attributes")
+ * parsers.newline
+ * parsers.unfreeze_trail
+ / writer.heading
+
+ local Heading = AtxHeading + SetextHeading
+ self.update_rule("Heading", Heading)
+ end
+ }
+end
+M.extensions.inline_code_attributes = function()
+ return {
+ name = "built-in inline_code_attributes syntax extension",
+ extend_writer = function()
+ end, extend_reader = function(self)
+ local writer = self.writer
+
+ local CodeWithAttributes = parsers.inticks
+ * Ct(parsers.attributes)
+ / writer.code
+
+ self.insert_pattern("Inline before Code",
+ CodeWithAttributes,
+ "CodeWithAttributes")
+ end
+ }
+end
+M.extensions.line_blocks = function()
+ return {
+ name = "built-in line_blocks syntax extension",
+ extend_writer = function(self)
+ function self.lineblock(lines)
+ if not self.is_writing then return "" end
+ local buffer = {}
+ for i = 1, #lines - 1 do
+ buffer[#buffer + 1] = { lines[i], self.hard_line_break }
+ end
+ buffer[#buffer + 1] = lines[#lines]
+
+ return {"\\markdownRendererLineBlockBegin\n"
+ ,buffer,
+ "\n\\markdownRendererLineBlockEnd "}
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
+
+ local LineBlock
+ = Ct((Cs(( (parsers.pipe * parsers.space) / ""
+ * ((parsers.space)/entities.char_entity("nbsp"))^0
+ * parsers.linechar^0 * (parsers.newline/""))
+ * (-parsers.pipe
+ * (parsers.space^1/" ")
+ * parsers.linechar^1
+ * (parsers.newline/"")
+ )^0
+ * (parsers.blankline/"")^0)
+ / self.parser_functions.parse_inlines)^1)
+ / writer.lineblock
+
+ self.insert_pattern("Block after Blockquote",
+ LineBlock, "LineBlock")
+ end
+ }
+end
+M.extensions.mark = function()
+ return {
+ name = "built-in mark syntax extension",
+ extend_writer = function(self)
+ function self.mark(s)
+ if self.flatten_inlines then return s end
+ return {"\\markdownRendererMark{", s, "}"}
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
+
+ local doubleequals = P("==")
+
+ local Mark
+ = parsers.between(V("Inline"), doubleequals, doubleequals)
+ / function (inlines) return writer.mark(inlines) end
+
+ self.add_special_character("=")
+ self.insert_pattern("Inline before LinkAndEmph",
+ Mark, "Mark")
+ end
+ }
+end
+M.extensions.link_attributes = function()
+ return {
+ name = "built-in link_attributes syntax extension",
+ extend_writer = function()
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local options = self.options
+
+ local define_reference_parser
+ = (parsers.check_trail / "")
+ * parsers.link_label
+ * parsers.colon
+ * parsers.spnlc * parsers.url
+ * ( parsers.spnlc_sep * parsers.title
+ * (parsers.spnlc * Ct(parsers.attributes))
+ * parsers.only_blank
+ + parsers.spnlc_sep * parsers.title * parsers.only_blank
+ + Cc("") * (parsers.spnlc * Ct(parsers.attributes))
+ * parsers.only_blank
+ + Cc("") * parsers.only_blank)
+
+ local ReferenceWithAttributes = define_reference_parser
+ / self.register_link
+
+ self.update_rule("Reference", ReferenceWithAttributes)
+
+
+ local LinkWithAttributesAndEmph
+ = Ct(parsers.link_and_emph_table * Cg(Cc(true),
+ "match_link_attributes"))
+ / self.defer_link_and_emphasis_processing
+
+ self.update_rule("LinkAndEmph", LinkWithAttributesAndEmph)
+
+ local AutoLinkUrlWithAttributes
+ = parsers.auto_link_url
+ * Ct(parsers.attributes)
+ / self.auto_link_url
+
+ self.insert_pattern("Inline before AutoLinkUrl",
+ AutoLinkUrlWithAttributes,
+ "AutoLinkUrlWithAttributes")
+
+ local AutoLinkEmailWithAttributes
+ = parsers.auto_link_email
+ * Ct(parsers.attributes)
+ / self.auto_link_email
+
+ self.insert_pattern("Inline before AutoLinkEmail",
+ AutoLinkEmailWithAttributes,
+ "AutoLinkEmailWithAttributes")
+
+ if options.relativeReferences then
+
+ local AutoLinkRelativeReferenceWithAttributes
+ = parsers.auto_link_relative_reference
+ * Ct(parsers.attributes)
+ / self.auto_link_url
+
+ self.insert_pattern(
+ "Inline before AutoLinkRelativeReference",
+ AutoLinkRelativeReferenceWithAttributes,
+ "AutoLinkRelativeReferenceWithAttributes")
+
+ end
+
+ end
+ }
+end
+M.extensions.notes = function(notes, inline_notes)
+ assert(notes or inline_notes)
+ return {
+ name = "built-in notes syntax extension",
+ extend_writer = function(self)
+ function self.note(s)
+ if self.flatten_inlines then return "" end
+ return {"\\markdownRendererNote{",s,"}"}
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
+
+ local rawnotes = parsers.rawnotes
+
+ if inline_notes then
+ local InlineNote
+ = parsers.circumflex
+ * ( parsers.link_label
+ / self.parser_functions.parse_inlines_no_inline_note)
+ / writer.note
+
+ self.insert_pattern("Inline after LinkAndEmph",
+ InlineNote, "InlineNote")
+ end
+ if notes then
+ local function strip_first_char(s)
+ return s:sub(2)
+ end
+
+ local RawNoteRef
+ = #(parsers.lbracket * parsers.circumflex)
+ * parsers.link_label / strip_first_char
+
+ -- like indirect_link
+ local function lookup_note(ref)
+ return writer.defer_call(function()
+ local found = rawnotes[self.normalize_tag(ref)]
+ if found then
+ return writer.note(
+ self.parser_functions.parse_blocks_nested(found))
+ else
+ return {"[",
+ self.parser_functions.parse_inlines("^" .. ref), "]"}
+ end
+ end)
+ end
+
+ local function register_note(ref,rawnote)
+ local normalized_tag = self.normalize_tag(ref)
+ if rawnotes[normalized_tag] == nil then
+ rawnotes[normalized_tag] = rawnote
+ end
+ return ""
+ end
+
+ local NoteRef = RawNoteRef / lookup_note
+
+ local optionally_indented_line
+ = parsers.check_optional_indent_and_any_trail * parsers.line
+
+ local blank
+ = parsers.check_optional_blank_indent_and_any_trail
+ * parsers.optionalspace * parsers.newline
+
+ local chunk
+ = Cs(parsers.line
+ * (optionally_indented_line - blank)^0)
+
+ local indented_blocks = function(bl)
+ return Cs( bl
+ * ( blank^1 * (parsers.check_optional_indent / "")
+ * parsers.check_code_trail
+ * -parsers.blankline * bl)^0)
+ end
+
+ local NoteBlock
+ = parsers.check_trail_no_rem
+ * RawNoteRef * parsers.colon
+ * parsers.spnlc * indented_blocks(chunk)
+ / register_note
+
+ local Reference = NoteBlock + parsers.Reference
+
+ self.update_rule("Reference", Reference)
+ self.insert_pattern("Inline before LinkAndEmph",
+ NoteRef, "NoteRef")
+ end
+
+ self.add_special_character("^")
+ end
+ }
+end
+M.extensions.pipe_tables = function(table_captions, table_attributes)
+
+ local function make_pipe_table_rectangular(rows)
+ local num_columns = #rows[2]
+ local rectangular_rows = {}
+ for i = 1, #rows do
+ local row = rows[i]
+ local rectangular_row = {}
+ for j = 1, num_columns do
+ rectangular_row[j] = row[j] or ""
+ end
+ table.insert(rectangular_rows, rectangular_row)
+ end
+ return rectangular_rows
+ end
+
+ local function pipe_table_row(allow_empty_first_column
+ , nonempty_column
+ , column_separator
+ , column)
+ local row_beginning
+ if allow_empty_first_column then
+ row_beginning = -- empty first column
+ #(parsers.spacechar^4
+ * column_separator)
+ * parsers.optionalspace
+ * column
+ * parsers.optionalspace
+ -- non-empty first column
+ + parsers.nonindentspace
+ * nonempty_column^-1
+ * parsers.optionalspace
+ else
+ row_beginning = parsers.nonindentspace
+ * nonempty_column^-1
+ * parsers.optionalspace
+ end
+
+ return Ct(row_beginning
+ * (-- single column with no leading pipes
+ #(column_separator
+ * parsers.optionalspace
+ * parsers.newline)
+ * column_separator
+ * parsers.optionalspace
+ -- single column with leading pipes or
+ -- more than a single column
+ + (column_separator
+ * parsers.optionalspace
+ * column
+ * parsers.optionalspace)^1
+ * (column_separator
+ * parsers.optionalspace)^-1))
+ end
+
+ return {
+ name = "built-in pipe_tables syntax extension",
+ extend_writer = function(self)
+ function self.table(rows, caption, attributes)
+ if not self.is_writing then return "" end
+ local buffer = {}
+ if attributes ~= nil then
+ table.insert(buffer,
+ "\\markdownRendererTableAttributeContextBegin\n")
+ table.insert(buffer, self.attributes(attributes))
+ end
+ table.insert(buffer,
+ {"\\markdownRendererTable{",
+ caption or "", "}{", #rows - 1, "}{",
+ #rows[1], "}"})
+ local temp = rows[2] -- put alignments on the first row
+ rows[2] = rows[1]
+ rows[1] = temp
+ for i, row in ipairs(rows) do
+ table.insert(buffer, "{")
+ for _, column in ipairs(row) do
+ if i > 1 then -- do not use braces for alignments
+ table.insert(buffer, "{")
+ end
+ table.insert(buffer, column)
+ if i > 1 then
+ table.insert(buffer, "}")
+ end
+ end
+ table.insert(buffer, "}")
+ end
+ if attributes ~= nil then
+ table.insert(buffer,
+ "\\markdownRendererTableAttributeContextEnd{}")
+ end
+ return buffer
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
+
+ local table_hline_separator = parsers.pipe + parsers.plus
+
+ local table_hline_column = (parsers.dash
+ - #(parsers.dash
+ * (parsers.spacechar
+ + table_hline_separator
+ + parsers.newline)))^1
+ * (parsers.colon * Cc("r")
+ + parsers.dash * Cc("d"))
+ + parsers.colon
+ * (parsers.dash
+ - #(parsers.dash
+ * (parsers.spacechar
+ + table_hline_separator
+ + parsers.newline)))^1
+ * (parsers.colon * Cc("c")
+ + parsers.dash * Cc("l"))
+
+ local table_hline = pipe_table_row(false
+ , table_hline_column
+ , table_hline_separator
+ , table_hline_column)
+
+ local table_caption_beginning
+ = ( parsers.check_minimal_blank_indent_and_any_trail_no_rem
+ * parsers.optionalspace * parsers.newline)^0
+ * parsers.check_minimal_indent_and_trail
+ * (P("Table")^-1 * parsers.colon)
+ * parsers.optionalspace
+
+ local function strip_trailing_spaces(s)
+ return s:gsub("%s*$","")
+ end
+
+ local table_row
+ = pipe_table_row(true
+ , (C((parsers.linechar - parsers.pipe)^1)
+ / strip_trailing_spaces
+ / self.parser_functions.parse_inlines)
+ , parsers.pipe
+ , (C((parsers.linechar - parsers.pipe)^0)
+ / strip_trailing_spaces
+ / self.parser_functions.parse_inlines))
+
+ local table_caption
+ if table_captions then
+ table_caption = #table_caption_beginning
+ * table_caption_beginning
+ if table_attributes then
+ table_caption = table_caption
+ * (C(((( parsers.linechar
+ - (parsers.attributes
+ * parsers.optionalspace
+ * parsers.newline
+ * -#( parsers.optionalspace
+ * parsers.linechar)))
+ + ( parsers.newline
+ * #( parsers.optionalspace
+ * parsers.linechar)
+ * C(parsers.optionalspace)
+ / writer.space))
+ * (parsers.linechar
+ - parsers.lbrace)^0)^1)
+ / self.parser_functions.parse_inlines)
+ * (parsers.newline
+ + ( Ct(parsers.attributes)
+ * parsers.optionalspace
+ * parsers.newline))
+ else
+ table_caption = table_caption
+ * C(( parsers.linechar
+ + ( parsers.newline
+ * #( parsers.optionalspace
+ * parsers.linechar)
+ * C(parsers.optionalspace)
+ / writer.space))^1)
+ / self.parser_functions.parse_inlines
+ * parsers.newline
+ end
+ else
+ table_caption = parsers.fail
+ end
+
+ local PipeTable
+ = Ct( table_row * parsers.newline
+ * (parsers.check_minimal_indent_and_trail / {})
+ * table_hline * parsers.newline
+ * ( (parsers.check_minimal_indent / {})
+ * table_row * parsers.newline)^0)
+ / make_pipe_table_rectangular
+ * table_caption^-1
+ / writer.table
+
+ self.insert_pattern("Block after Blockquote",
+ PipeTable, "PipeTable")
+ end
+ }
+end
+M.extensions.raw_inline = function()
+ return {
+ name = "built-in raw_inline syntax extension",
+ extend_writer = function(self)
+ local options = self.options
+
+ function self.rawInline(s, attr)
+ if not self.is_writing then return "" end
+ if self.flatten_inlines then return s end
+ local name = util.cache_verbatim(options.cacheDir, s)
+ return {"\\markdownRendererInputRawInline{",
+ name,"}{", self.string(attr),"}"}
+ end
+ end, extend_reader = function(self)
+ local writer = self.writer
+
+ local RawInline = parsers.inticks
+ * parsers.raw_attribute
+ / writer.rawInline
+
+ self.insert_pattern("Inline before Code",
+ RawInline, "RawInline")
+ end
+ }
+end
+M.extensions.strike_through = function()
+ return {
+ name = "built-in strike_through syntax extension",
+ extend_writer = function(self)
+ function self.strike_through(s)
+ if self.flatten_inlines then return s end
+ return {"\\markdownRendererStrikeThrough{",s,"}"}
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
+
+ local StrikeThrough = (
+ parsers.between(parsers.Inline, parsers.doubletildes,
+ parsers.doubletildes)
+ ) / writer.strike_through
+
+ self.insert_pattern("Inline after LinkAndEmph",
+ StrikeThrough, "StrikeThrough")
+
+ self.add_special_character("~")
+ end
+ }
+end
+M.extensions.subscripts = function()
+ return {
+ name = "built-in subscripts syntax extension",
+ extend_writer = function(self)
+ function self.subscript(s)
+ if self.flatten_inlines then return s end
+ return {"\\markdownRendererSubscript{",s,"}"}
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
+
+ local Subscript = (
+ parsers.between(parsers.Str, parsers.tilde, parsers.tilde)
+ ) / writer.subscript
+
+ self.insert_pattern("Inline after LinkAndEmph",
+ Subscript, "Subscript")
+
+ self.add_special_character("~")
+ end
+ }
+end
+M.extensions.superscripts = function()
+ return {
+ name = "built-in superscripts syntax extension",
+ extend_writer = function(self)
+ function self.superscript(s)
+ if self.flatten_inlines then return s end
+ return {"\\markdownRendererSuperscript{",s,"}"}
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
+
+ local Superscript = (
+ parsers.between(parsers.Str, parsers.circumflex,
+ parsers.circumflex)
+ ) / writer.superscript
+
+ self.insert_pattern("Inline after LinkAndEmph",
+ Superscript, "Superscript")
+
+ self.add_special_character("^")
+ end
+ }
+end
+M.extensions.tex_math = function(tex_math_dollars,
+ tex_math_single_backslash,
+ tex_math_double_backslash)
+ return {
+ name = "built-in tex_math syntax extension",
+ extend_writer = function(self)
+ function self.display_math(s)
+ if self.flatten_inlines then return s end
+ return {"\\markdownRendererDisplayMath{",self.math(s),"}"}
+ end
+ function self.inline_math(s)
+ if self.flatten_inlines then return s end
+ return {"\\markdownRendererInlineMath{",self.math(s),"}"}
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
+
+ local function between(p, starter, ender)
+ return (starter * Cs(p * (p - ender)^0) * ender)
+ end
+
+ local function strip_preceding_whitespaces(str)
+ return str:gsub("^%s*(.-)$", "%1")
+ end
+
+ local allowed_before_closing
+ = B( parsers.backslash * parsers.any
+ + parsers.any * (parsers.any - parsers.backslash))
+
+ local allowed_before_closing_no_space
+ = B( parsers.backslash * parsers.any
+ + parsers.any * (parsers.nonspacechar - parsers.backslash))
+
+ local dollar_math_content
+ = (parsers.newline * (parsers.check_optional_indent / "")
+ + parsers.backslash^-1
+ * parsers.linechar)
+ - parsers.blankline^2
+ - parsers.dollar
+
+ local inline_math_opening_dollars = parsers.dollar
+ * #(parsers.nonspacechar)
+
+ local inline_math_closing_dollars
+ = allowed_before_closing_no_space
+ * parsers.dollar
+ * -#(parsers.digit)
+
+ local inline_math_dollars = between(Cs( dollar_math_content),
+ inline_math_opening_dollars,
+ inline_math_closing_dollars)
+
+ local display_math_opening_dollars = parsers.dollar
+ * parsers.dollar
+
+ local display_math_closing_dollars = parsers.dollar
+ * parsers.dollar
+
+ local display_math_dollars = between(Cs( dollar_math_content),
+ display_math_opening_dollars,
+ display_math_closing_dollars)
+ local backslash_math_content
+ = (parsers.newline * (parsers.check_optional_indent / "")
+ + parsers.linechar)
+ - parsers.blankline^2
+ local inline_math_opening_double = parsers.backslash
+ * parsers.backslash
+ * parsers.lparent
+
+ local inline_math_closing_double = allowed_before_closing
+ * parsers.spacechar^0
+ * parsers.backslash
+ * parsers.backslash
+ * parsers.rparent
+
+ local inline_math_double = between(Cs( backslash_math_content),
+ inline_math_opening_double,
+ inline_math_closing_double)
+ / strip_preceding_whitespaces
+
+ local display_math_opening_double = parsers.backslash
+ * parsers.backslash
+ * parsers.lbracket
+
+ local display_math_closing_double = allowed_before_closing
+ * parsers.spacechar^0
+ * parsers.backslash
+ * parsers.backslash
+ * parsers.rbracket
+
+ local display_math_double = between(Cs( backslash_math_content),
+ display_math_opening_double,
+ display_math_closing_double)
+ / strip_preceding_whitespaces
+ local inline_math_opening_single = parsers.backslash
+ * parsers.lparent
+
+ local inline_math_closing_single = allowed_before_closing
+ * parsers.spacechar^0
+ * parsers.backslash
+ * parsers.rparent
+
+ local inline_math_single = between(Cs( backslash_math_content),
+ inline_math_opening_single,
+ inline_math_closing_single)
+ / strip_preceding_whitespaces
+
+ local display_math_opening_single = parsers.backslash
+ * parsers.lbracket
+
+ local display_math_closing_single = allowed_before_closing
+ * parsers.spacechar^0
+ * parsers.backslash
+ * parsers.rbracket
+
+ local display_math_single = between(Cs( backslash_math_content),
+ display_math_opening_single,
+ display_math_closing_single)
+ / strip_preceding_whitespaces
+
+ local display_math = parsers.fail
+
+ local inline_math = parsers.fail
+
+ if tex_math_dollars then
+ display_math = display_math + display_math_dollars
+ inline_math = inline_math + inline_math_dollars
+ end
+
+ if tex_math_double_backslash then
+ display_math = display_math + display_math_double
+ inline_math = inline_math + inline_math_double
+ end
+
+ if tex_math_single_backslash then
+ display_math = display_math + display_math_single
+ inline_math = inline_math + inline_math_single
+ end
+
+ local TexMath = display_math / writer.display_math
+ + inline_math / writer.inline_math
+
+ self.insert_pattern("Inline after LinkAndEmph",
+ TexMath, "TexMath")
+
+ if tex_math_dollars then
+ self.add_special_character("$")
+ end
+
+ if tex_math_single_backslash or tex_math_double_backslash then
+ self.add_special_character("\\")
+ self.add_special_character("[")
+ self.add_special_character("]")
+ self.add_special_character(")")
+ self.add_special_character("(")
+ end
+ end
+ }
+end
+M.extensions.jekyll_data = function(expect_jekyll_data,
+ ensure_jekyll_data)
+ return {
+ name = "built-in jekyll_data syntax extension",
+ extend_writer = function(self)
+ function self.jekyllData(d, t, p)
+ if not self.is_writing then return "" end
+
+ local buf = {}
+
+ local keys = {}
+ for k, _ in pairs(d) do
+ table.insert(keys, k)
+ end
+ table.sort(keys, function(first, second)
+ if type(first) ~= type(second) then
+ return type(first) < type(second)
+ else
+ return first < second
+ end
+ end)
+
+ if not p then
+ table.insert(buf, "\\markdownRendererJekyllDataBegin")
+ end
+
+ local is_sequence = false
+ if #d > 0 and #d == #keys then
+ for i=1, #d do
+ if d[i] == nil then
+ goto not_a_sequence
+ end
+ end
+ is_sequence = true
+ end
+ ::not_a_sequence::
+
+ if is_sequence then
+ table.insert(buf,
+ "\\markdownRendererJekyllDataSequenceBegin{")
+ table.insert(buf, self.identifier(p or "null"))
+ table.insert(buf, "}{")
+ table.insert(buf, #keys)
+ table.insert(buf, "}")
+ else
+ table.insert(buf, "\\markdownRendererJekyllDataMappingBegin{")
+ table.insert(buf, self.identifier(p or "null"))
+ table.insert(buf, "}{")
+ table.insert(buf, #keys)
+ table.insert(buf, "}")
+ end
+
+ for _, k in ipairs(keys) do
+ local v = d[k]
+ local typ = type(v)
+ k = tostring(k or "null")
+ if typ == "table" and next(v) ~= nil then
+ table.insert(
+ buf,
+ self.jekyllData(v, t, k)
+ )
+ else
+ k = self.identifier(k)
+ v = tostring(v)
+ if typ == "boolean" then
+ table.insert(buf, "\\markdownRendererJekyllDataBoolean{")
+ table.insert(buf, k)
+ table.insert(buf, "}{")
+ table.insert(buf, v)
+ table.insert(buf, "}")
+ elseif typ == "number" then
+ table.insert(buf, "\\markdownRendererJekyllDataNumber{")
+ table.insert(buf, k)
+ table.insert(buf, "}{")
+ table.insert(buf, v)
+ table.insert(buf, "}")
+ elseif typ == "string" then
+ table.insert(buf,
+ "\\markdownRendererJekyllDataProgrammaticString{")
+ table.insert(buf, k)
+ table.insert(buf, "}{")
+ table.insert(buf, self.identifier(v))
+ table.insert(buf, "}")
+ table.insert(buf,
+ "\\markdownRendererJekyllDataTypographicString{")
+ table.insert(buf, k)
+ table.insert(buf, "}{")
+ table.insert(buf, t(v))
+ table.insert(buf, "}")
+ elseif typ == "table" then
+ table.insert(buf, "\\markdownRendererJekyllDataEmpty{")
+ table.insert(buf, k)
+ table.insert(buf, "}")
+ else
+ local error = self.error(format(
+ "Unexpected type %s for value of "
+ .. "YAML key %s", typ, k))
+ table.insert(buf, error)
+ end
+ end
+ end
+
+ if is_sequence then
+ table.insert(buf, "\\markdownRendererJekyllDataSequenceEnd")
+ else
+ table.insert(buf, "\\markdownRendererJekyllDataMappingEnd")
+ end
+
+ if not p then
+ table.insert(buf, "\\markdownRendererJekyllDataEnd")
+ end
+
+ return buf
+ end
+ end, extend_reader = function(self)
+ local parsers = self.parsers
+ local writer = self.writer
+
+ local JekyllData
+ = Cmt( C((parsers.line - P("---") - P("..."))^0)
+ , function(s, i, text) -- luacheck: ignore s i
+ local data
+ local ran_ok, _ = pcall(function()
+ -- TODO: Use `require("tinyyaml")` in TeX Live 2023
+ local tinyyaml = require("markdown-tinyyaml")
+ data = tinyyaml.parse(text, {timestamps=false})
+ end)
+ if ran_ok and data ~= nil then
+ return true, writer.jekyllData(data, function(s)
+ return self.parser_functions.parse_blocks_nested(s)
+ end, nil)
+ else
+ return false
+ end
+ end
+ )
+
+ local UnexpectedJekyllData
+ = P("---")
+ * parsers.blankline / 0
+ -- if followed by blank, it's thematic break
+ * #(-parsers.blankline)
+ * JekyllData
+ * (P("---") + P("..."))
+
+ local ExpectedJekyllData
+ = ( P("---")
+ * parsers.blankline / 0
+ -- if followed by blank, it's thematic break
+ * #(-parsers.blankline)
+ )^-1
+ * JekyllData
+ * (P("---") + P("..."))^-1
+
+ if ensure_jekyll_data then
+ ExpectedJekyllData = ExpectedJekyllData
+ * parsers.eof
+ else
+ ExpectedJekyllData = ( ExpectedJekyllData
+ * (V("Blank")^0 / writer.interblocksep)
+ )^-1
+ end
+
+ self.insert_pattern("Block before Blockquote",
+ UnexpectedJekyllData, "UnexpectedJekyllData")
+ if expect_jekyll_data then
+ self.update_rule("ExpectedJekyllData", ExpectedJekyllData)
+ end
+ end
+ }
+end
+function M.new(options)
+ options = options or {}
+ setmetatable(options, { __index = function (_, key)
+ return defaultOptions[key] end })
+ if options.singletonCache and singletonCache.convert then
+ for k, v in pairs(defaultOptions) do
+ if type(v) == "table" then
+ for i = 1, math.max(#singletonCache.options[k], #options[k]) do
+ if singletonCache.options[k][i] ~= options[k][i] then
+ goto miss
+ end
+ end
+ elseif k ~= "cacheDir"
+ and singletonCache.options[k] ~= options[k] then
+ goto miss
+ end
+ end
+ return singletonCache.convert
+ end
+ ::miss::
+ local extensions = {}
+
+ if options.bracketedSpans then
+ local bracketed_spans_extension = M.extensions.bracketed_spans()
+ table.insert(extensions, bracketed_spans_extension)
+ end
+
+ if options.contentBlocks then
+ local content_blocks_extension = M.extensions.content_blocks(
+ options.contentBlocksLanguageMap)
+ table.insert(extensions, content_blocks_extension)
+ end
+
+ if options.definitionLists then
+ local definition_lists_extension = M.extensions.definition_lists(
+ options.tightLists)
+ table.insert(extensions, definition_lists_extension)
+ end
+
+ if options.fencedCode then
+ local fenced_code_extension = M.extensions.fenced_code(
+ options.blankBeforeCodeFence,
+ options.fencedCodeAttributes,
+ options.rawAttribute)
+ table.insert(extensions, fenced_code_extension)
+ end
+
+ if options.fencedDivs then
+ local fenced_div_extension = M.extensions.fenced_divs(
+ options.blankBeforeDivFence)
+ table.insert(extensions, fenced_div_extension)
+ end
+
+ if options.headerAttributes then
+ local header_attributes_extension = M.extensions.header_attributes()
+ table.insert(extensions, header_attributes_extension)
+ end
+
+ if options.inlineCodeAttributes then
+ local inline_code_attributes_extension =
+ M.extensions.inline_code_attributes()
+ table.insert(extensions, inline_code_attributes_extension)
+ end
+
+ if options.jekyllData then
+ local jekyll_data_extension = M.extensions.jekyll_data(
+ options.expectJekyllData, options.ensureJekyllData)
+ table.insert(extensions, jekyll_data_extension)
+ end
+
+ if options.linkAttributes then
+ local link_attributes_extension =
+ M.extensions.link_attributes()
+ table.insert(extensions, link_attributes_extension)
+ end
+
+ if options.lineBlocks then
+ local line_block_extension = M.extensions.line_blocks()
+ table.insert(extensions, line_block_extension)
+ end
+
+ if options.mark then
+ local mark_extension = M.extensions.mark()
+ table.insert(extensions, mark_extension)
+ end
+
+ if options.pipeTables then
+ local pipe_tables_extension = M.extensions.pipe_tables(
+ options.tableCaptions, options.tableAttributes)
+ table.insert(extensions, pipe_tables_extension)
+ end
+
+ if options.rawAttribute then
+ local raw_inline_extension = M.extensions.raw_inline()
+ table.insert(extensions, raw_inline_extension)
+ end
+
+ if options.strikeThrough then
+ local strike_through_extension = M.extensions.strike_through()
+ table.insert(extensions, strike_through_extension)
+ end
+
+ if options.subscripts then
+ local subscript_extension = M.extensions.subscripts()
+ table.insert(extensions, subscript_extension)
+ end
+
+ if options.superscripts then
+ local superscript_extension = M.extensions.superscripts()
+ table.insert(extensions, superscript_extension)
+ end
+
+ if options.texMathDollars or
+ options.texMathSingleBackslash or
+ options.texMathDoubleBackslash then
+ local tex_math_extension = M.extensions.tex_math(
+ options.texMathDollars,
+ options.texMathSingleBackslash,
+ options.texMathDoubleBackslash)
+ table.insert(extensions, tex_math_extension)
+ end
+
+ if options.notes or options.inlineNotes then
+ local notes_extension = M.extensions.notes(
+ options.notes, options.inlineNotes)
+ table.insert(extensions, notes_extension)
+ end
+
+ if options.citations then
+ local citations_extension
+ = M.extensions.citations(options.citationNbsps)
+ table.insert(extensions, citations_extension)
+ end
+
+ if options.fancyLists then
+ local fancy_lists_extension = M.extensions.fancy_lists()
+ table.insert(extensions, fancy_lists_extension)
+ end
+ for _, user_extension_filename in ipairs(options.extensions) do
+ local user_extension = (function(filename)
+ local pathname = assert(kpse.find_file(filename),
+ [[Could not locate user-defined syntax extension "]]
+ .. filename)
+ local input_file = assert(io.open(pathname, "r"),
+ [[Could not open user-defined syntax extension "]]
+ .. pathname .. [[" for reading]])
+ local input = assert(input_file:read("*a"))
+ assert(input_file:close())
+ local user_extension, err = load([[
+ local sandbox = {}
+ setmetatable(sandbox, {__index = _G})
+ _ENV = sandbox
+ ]] .. input)()
+ assert(user_extension,
+ [[Failed to compile user-defined syntax extension "]]
+ .. pathname .. [[": ]] .. (err or [[]]))
+ assert(user_extension.api_version ~= nil,
+ [[User-defined syntax extension "]] .. pathname
+ .. [[" does not specify mandatory field "api_version"]])
+ assert(type(user_extension.api_version) == "number",
+ [[User-defined syntax extension "]] .. pathname
+ .. [[" specifies field "api_version" of type "]]
+ .. type(user_extension.api_version)
+ .. [[" but "number" was expected]])
+ assert(user_extension.api_version > 0
+ and user_extension.api_version
+ <= metadata.user_extension_api_version,
+ [[User-defined syntax extension "]] .. pathname
+ .. [[" uses syntax extension API version "]]
+ .. user_extension.api_version .. [[ but markdown.lua ]]
+ .. metadata.version .. [[ uses API version ]]
+ .. metadata.user_extension_api_version
+ .. [[, which is incompatible]])
+
+ assert(user_extension.grammar_version ~= nil,
+ [[User-defined syntax extension "]] .. pathname
+ .. [[" does not specify mandatory field "grammar_version"]])
+ assert(type(user_extension.grammar_version) == "number",
+ [[User-defined syntax extension "]] .. pathname
+ .. [[" specifies field "grammar_version" of type "]]
+ .. type(user_extension.grammar_version)
+ .. [[" but "number" was expected]])
+ assert(user_extension.grammar_version == metadata.grammar_version,
+ [[User-defined syntax extension "]] .. pathname
+ .. [[" uses grammar version "]]
+ .. user_extension.grammar_version
+ .. [[ but markdown.lua ]] .. metadata.version
+ .. [[ uses grammar version ]] .. metadata.grammar_version
+ .. [[, which is incompatible]])
+
+ assert(user_extension.finalize_grammar ~= nil,
+ [[User-defined syntax extension "]] .. pathname
+ .. [[" does not specify mandatory "finalize_grammar" field]])
+ assert(type(user_extension.finalize_grammar) == "function",
+ [[User-defined syntax extension "]] .. pathname
+ .. [[" specifies field "finalize_grammar" of type "]]
+ .. type(user_extension.finalize_grammar)
+ .. [[" but "function" was expected]])
+ local extension = {
+ name = [[user-defined "]] .. pathname .. [[" syntax extension]],
+ extend_reader = user_extension.finalize_grammar,
+ extend_writer = function() end,
+ }
+ return extension
+ end)(user_extension_filename)
+ table.insert(extensions, user_extension)
+ end
+ local writer = M.writer.new(options)
+ local reader = M.reader.new(writer, options)
+ local convert = reader.finalize_grammar(extensions)
+ collectgarbage("collect")
+ if options.singletonCache then
+ local singletonCacheOptions = {}
+ for k, v in pairs(options) do
+ singletonCacheOptions[k] = v
+ end
+ setmetatable(singletonCacheOptions,
+ { __index = function (_, key)
+ return defaultOptions[key] end })
+ singletonCache.options = singletonCacheOptions
+ singletonCache.convert = convert
+ end
+ return convert
+end
+return M
diff --git a/Master/texmf-dist/tex/luatex/markdown/markdown-tinyyaml.lua b/Master/texmf-dist/tex/luatex/markdown/markdown-tinyyaml.lua
index 36cef293ed9..25b351f7e40 100644
--- a/Master/texmf-dist/tex/luatex/markdown/markdown-tinyyaml.lua
+++ b/Master/texmf-dist/tex/luatex/markdown/markdown-tinyyaml.lua
@@ -253,7 +253,9 @@ function Parser:parsestring(line, stopper)
end
line = ssub(line, 2)
end
- return rtrim(buf), line
+ buf = rtrim(buf)
+ local val = tonumber(buf) or buf
+ return val, line
end
local function isemptyline(line)
diff --git a/Master/texmf-dist/tex/luatex/markdown/markdown.lua b/Master/texmf-dist/tex/luatex/markdown/markdown.lua
index e65712cdcb6..7d1d4d6cde8 100644
--- a/Master/texmf-dist/tex/luatex/markdown/markdown.lua
+++ b/Master/texmf-dist/tex/luatex/markdown/markdown.lua
@@ -9,18 +9,18 @@
-- permit persons to whom the Software is furnished to do so, subject to
-- the following conditions:
--
--- The above copyright notice and this permission notice shall be included
--- in all copies or substantial portions of the Software.
+-- The above copyright notice and this permission notice shall be
+-- included in all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
--- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+-- MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND NONINFRINGEMENT.
-- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
--
--- Copyright (C) 2016-2024 Vít Starý Novotný
+-- Copyright (C) 2016-2024 Vít Starý Novotný, Andrej Genčur
--
-- This work may be distributed and/or modified under the
-- conditions of the LaTeX Project Public License, either version 1.3
@@ -58,68 +58,23 @@
-- those in the standard .ins files.
--
local metadata = {
- version = "3.5.0-0-gfd01a252",
- comment = "A module for the conversion from markdown to plain TeX",
- author = "John MacFarlane, Hans Hagen, Vít Starý Novotný",
+ version = "3.7.0-0-g98dece19",
+ comment = "A module for the conversion from markdown "
+ .. "to plain TeX",
+ author = "John MacFarlane, Hans Hagen, Vít Starý Novotný, "
+ .. "Andrej Genčur",
copyright = {"2009-2016 John MacFarlane, Hans Hagen",
- "2016-2023 Vít Starý Novotný"},
+ "2016-2024 Vít Starý Novotný, Andrej Genčur"},
license = "LPPL 1.3c"
}
-if not modules then modules = { } end
-modules['markdown'] = metadata
-local lpeg = require("lpeg")
-local unicode = require("unicode")
local md5 = require("md5");
-(function()
- local should_initialize = package.loaded.kpse == nil
- or tex.initialize ~= nil
- kpse = require("kpse")
- if should_initialize then
- kpse.set_program_name("luatex")
- end
-end)()
-local uni_algos = require("lua-uni-algos")
local M = {metadata = metadata}
-local walkable_syntax = {
- Block = {
- "Blockquote",
- "Verbatim",
- "ThematicBreak",
- "BulletList",
- "OrderedList",
- "DisplayHtml",
- "Heading",
- },
- BlockOrParagraph = {
- "Block",
- "Paragraph",
- "Plain",
- },
- Inline = {
- "Str",
- "Space",
- "Endline",
- "EndlineBreak",
- "LinkAndEmph",
- "Code",
- "AutoLinkUrl",
- "AutoLinkEmail",
- "AutoLinkRelativeReference",
- "InlineHtml",
- "HtmlEntity",
- "EscapedChar",
- "Smart",
- "Symbol",
- },
-}
local defaultOptions = {}
-defaultOptions.eagerCache = false
+defaultOptions.eagerCache = true
defaultOptions.singletonCache = true
-local singletonCache = {
- convert = nil,
- options = nil,
-}
+defaultOptions.unicodeNormalization = true
+defaultOptions.unicodeNormalizationForm = "nfc"
defaultOptions.cacheDir = "."
defaultOptions.contentBlocksLanguageMap = "markdown-languages.json"
defaultOptions.debugExtensionsFileName = "debug-extensions.json"
@@ -139,9 +94,8 @@ defaultOptions.contentBlocks = false
defaultOptions.contentLevel = "block"
defaultOptions.debugExtensions = false
defaultOptions.definitionLists = false
+defaultOptions.ensureJekyllData = false
defaultOptions.expectJekyllData = false
-metadata.user_extension_api_version = 2
-metadata.grammar_version = 4
defaultOptions.extensions = {}
defaultOptions.fancyLists = false
defaultOptions.fencedCode = true
@@ -182,21 +136,12 @@ defaultOptions.texMathDoubleBackslash = false
defaultOptions.texMathSingleBackslash = false
defaultOptions.tightLists = true
defaultOptions.underscores = true
-local upper, format, length =
- string.upper, string.format, string.len
-local P, R, S, V, C, Cg, Cb, Cmt, Cc, Ct, B, Cs, Cp, any =
- lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.C, lpeg.Cg, lpeg.Cb,
- lpeg.Cmt, lpeg.Cc, lpeg.Ct, lpeg.B, lpeg.Cs, lpeg.Cp, lpeg.P(1)
local util = {}
-function util.err(msg, exit_code)
- io.stderr:write("markdown.lua: " .. msg .. "\n")
- os.exit(exit_code or 1)
-end
function util.cache(dir, string, salt, transform, suffix)
local digest = md5.sumhexa(string .. (salt or ""))
local name = util.pathname(dir, digest .. suffix)
local file = io.open(name, "r")
- if file == nil then -- If no cache entry exists, then create a new one.
+ if file == nil then -- If no cache entry exists, create a new one.
file = assert(io.open(name, "w"),
[[Could not open file "]] .. name .. [[" for writing]])
local result = string
@@ -208,116 +153,6 @@ function util.cache(dir, string, salt, transform, suffix)
end
return name
end
-function util.cache_verbatim(dir, string)
- local name = util.cache(dir, string, nil, nil, ".verbatim")
- return name
-end
-function util.table_copy(t)
- local u = { }
- for k, v in pairs(t) do u[k] = v end
- return setmetatable(u, getmetatable(t))
-end
-function util.encode_json_string(s)
- s = s:gsub([[\]], [[\\]])
- s = s:gsub([["]], [[\"]])
- return [["]] .. s .. [["]]
-end
-function util.expand_tabs_in_line(s, tabstop)
- local tab = tabstop or 4
- local corr = 0
- return (s:gsub("()\t", function(p)
- local sp = tab - (p - 1 + corr) % tab
- corr = corr - 1 + sp
- return string.rep(" ", sp)
- end))
-end
-function util.walk(t, f)
- local typ = type(t)
- if typ == "string" then
- f(t)
- elseif typ == "table" then
- local i = 1
- local n
- n = t[i]
- while n do
- util.walk(n, f)
- i = i + 1
- n = t[i]
- end
- elseif typ == "function" then
- local ok, val = pcall(t)
- if ok then
- util.walk(val,f)
- end
- else
- f(tostring(t))
- end
-end
-function util.flatten(ary)
- local new = {}
- for _,v in ipairs(ary) do
- if type(v) == "table" then
- for _,w in ipairs(util.flatten(v)) do
- new[#new + 1] = w
- end
- else
- new[#new + 1] = v
- end
- end
- return new
-end
-function util.rope_to_string(rope)
- local buffer = {}
- util.walk(rope, function(x) buffer[#buffer + 1] = x end)
- return table.concat(buffer)
-end
-function util.rope_last(rope)
- if #rope == 0 then
- return nil
- else
- local l = rope[#rope]
- if type(l) == "table" then
- return util.rope_last(l)
- else
- return l
- end
- end
-end
-function util.intersperse(ary, x)
- local new = {}
- local l = #ary
- for i,v in ipairs(ary) do
- local n = #new
- new[n + 1] = v
- if i ~= l then
- new[n + 2] = x
- end
- end
- return new
-end
-function util.map(ary, f)
- local new = {}
- for i,v in ipairs(ary) do
- new[i] = f(v)
- end
- return new
-end
-function util.escaper(char_escapes, string_escapes)
- local char_escapes_list = ""
- for i,_ in pairs(char_escapes) do
- char_escapes_list = char_escapes_list .. i
- end
- local escapable = S(char_escapes_list) / char_escapes
- if string_escapes then
- for k,v in pairs(string_escapes) do
- escapable = P(k) / v + escapable
- end
- end
- local escape_string = Cs((escapable + any)^0)
- return function(s)
- return lpeg.match(escape_string, s)
- end
-end
function util.pathname(dir, file)
if #dir == 0 then
return file
@@ -325,8021 +160,70 @@ function util.pathname(dir, file)
return dir .. "/" .. file
end
end
-local entities = {}
-
-local character_entities = {
- ["Tab"] = 9,
- ["NewLine"] = 10,
- ["excl"] = 33,
- ["QUOT"] = 34,
- ["quot"] = 34,
- ["num"] = 35,
- ["dollar"] = 36,
- ["percnt"] = 37,
- ["AMP"] = 38,
- ["amp"] = 38,
- ["apos"] = 39,
- ["lpar"] = 40,
- ["rpar"] = 41,
- ["ast"] = 42,
- ["midast"] = 42,
- ["plus"] = 43,
- ["comma"] = 44,
- ["period"] = 46,
- ["sol"] = 47,
- ["colon"] = 58,
- ["semi"] = 59,
- ["LT"] = 60,
- ["lt"] = 60,
- ["nvlt"] = {60, 8402},
- ["bne"] = {61, 8421},
- ["equals"] = 61,
- ["GT"] = 62,
- ["gt"] = 62,
- ["nvgt"] = {62, 8402},
- ["quest"] = 63,
- ["commat"] = 64,
- ["lbrack"] = 91,
- ["lsqb"] = 91,
- ["bsol"] = 92,
- ["rbrack"] = 93,
- ["rsqb"] = 93,
- ["Hat"] = 94,
- ["UnderBar"] = 95,
- ["lowbar"] = 95,
- ["DiacriticalGrave"] = 96,
- ["grave"] = 96,
- ["fjlig"] = {102, 106},
- ["lbrace"] = 123,
- ["lcub"] = 123,
- ["VerticalLine"] = 124,
- ["verbar"] = 124,
- ["vert"] = 124,
- ["rbrace"] = 125,
- ["rcub"] = 125,
- ["NonBreakingSpace"] = 160,
- ["nbsp"] = 160,
- ["iexcl"] = 161,
- ["cent"] = 162,
- ["pound"] = 163,
- ["curren"] = 164,
- ["yen"] = 165,
- ["brvbar"] = 166,
- ["sect"] = 167,
- ["Dot"] = 168,
- ["DoubleDot"] = 168,
- ["die"] = 168,
- ["uml"] = 168,
- ["COPY"] = 169,
- ["copy"] = 169,
- ["ordf"] = 170,
- ["laquo"] = 171,
- ["not"] = 172,
- ["shy"] = 173,
- ["REG"] = 174,
- ["circledR"] = 174,
- ["reg"] = 174,
- ["macr"] = 175,
- ["strns"] = 175,
- ["deg"] = 176,
- ["PlusMinus"] = 177,
- ["plusmn"] = 177,
- ["pm"] = 177,
- ["sup2"] = 178,
- ["sup3"] = 179,
- ["DiacriticalAcute"] = 180,
- ["acute"] = 180,
- ["micro"] = 181,
- ["para"] = 182,
- ["CenterDot"] = 183,
- ["centerdot"] = 183,
- ["middot"] = 183,
- ["Cedilla"] = 184,
- ["cedil"] = 184,
- ["sup1"] = 185,
- ["ordm"] = 186,
- ["raquo"] = 187,
- ["frac14"] = 188,
- ["frac12"] = 189,
- ["half"] = 189,
- ["frac34"] = 190,
- ["iquest"] = 191,
- ["Agrave"] = 192,
- ["Aacute"] = 193,
- ["Acirc"] = 194,
- ["Atilde"] = 195,
- ["Auml"] = 196,
- ["Aring"] = 197,
- ["angst"] = 197,
- ["AElig"] = 198,
- ["Ccedil"] = 199,
- ["Egrave"] = 200,
- ["Eacute"] = 201,
- ["Ecirc"] = 202,
- ["Euml"] = 203,
- ["Igrave"] = 204,
- ["Iacute"] = 205,
- ["Icirc"] = 206,
- ["Iuml"] = 207,
- ["ETH"] = 208,
- ["Ntilde"] = 209,
- ["Ograve"] = 210,
- ["Oacute"] = 211,
- ["Ocirc"] = 212,
- ["Otilde"] = 213,
- ["Ouml"] = 214,
- ["times"] = 215,
- ["Oslash"] = 216,
- ["Ugrave"] = 217,
- ["Uacute"] = 218,
- ["Ucirc"] = 219,
- ["Uuml"] = 220,
- ["Yacute"] = 221,
- ["THORN"] = 222,
- ["szlig"] = 223,
- ["agrave"] = 224,
- ["aacute"] = 225,
- ["acirc"] = 226,
- ["atilde"] = 227,
- ["auml"] = 228,
- ["aring"] = 229,
- ["aelig"] = 230,
- ["ccedil"] = 231,
- ["egrave"] = 232,
- ["eacute"] = 233,
- ["ecirc"] = 234,
- ["euml"] = 235,
- ["igrave"] = 236,
- ["iacute"] = 237,
- ["icirc"] = 238,
- ["iuml"] = 239,
- ["eth"] = 240,
- ["ntilde"] = 241,
- ["ograve"] = 242,
- ["oacute"] = 243,
- ["ocirc"] = 244,
- ["otilde"] = 245,
- ["ouml"] = 246,
- ["div"] = 247,
- ["divide"] = 247,
- ["oslash"] = 248,
- ["ugrave"] = 249,
- ["uacute"] = 250,
- ["ucirc"] = 251,
- ["uuml"] = 252,
- ["yacute"] = 253,
- ["thorn"] = 254,
- ["yuml"] = 255,
- ["Amacr"] = 256,
- ["amacr"] = 257,
- ["Abreve"] = 258,
- ["abreve"] = 259,
- ["Aogon"] = 260,
- ["aogon"] = 261,
- ["Cacute"] = 262,
- ["cacute"] = 263,
- ["Ccirc"] = 264,
- ["ccirc"] = 265,
- ["Cdot"] = 266,
- ["cdot"] = 267,
- ["Ccaron"] = 268,
- ["ccaron"] = 269,
- ["Dcaron"] = 270,
- ["dcaron"] = 271,
- ["Dstrok"] = 272,
- ["dstrok"] = 273,
- ["Emacr"] = 274,
- ["emacr"] = 275,
- ["Edot"] = 278,
- ["edot"] = 279,
- ["Eogon"] = 280,
- ["eogon"] = 281,
- ["Ecaron"] = 282,
- ["ecaron"] = 283,
- ["Gcirc"] = 284,
- ["gcirc"] = 285,
- ["Gbreve"] = 286,
- ["gbreve"] = 287,
- ["Gdot"] = 288,
- ["gdot"] = 289,
- ["Gcedil"] = 290,
- ["Hcirc"] = 292,
- ["hcirc"] = 293,
- ["Hstrok"] = 294,
- ["hstrok"] = 295,
- ["Itilde"] = 296,
- ["itilde"] = 297,
- ["Imacr"] = 298,
- ["imacr"] = 299,
- ["Iogon"] = 302,
- ["iogon"] = 303,
- ["Idot"] = 304,
- ["imath"] = 305,
- ["inodot"] = 305,
- ["IJlig"] = 306,
- ["ijlig"] = 307,
- ["Jcirc"] = 308,
- ["jcirc"] = 309,
- ["Kcedil"] = 310,
- ["kcedil"] = 311,
- ["kgreen"] = 312,
- ["Lacute"] = 313,
- ["lacute"] = 314,
- ["Lcedil"] = 315,
- ["lcedil"] = 316,
- ["Lcaron"] = 317,
- ["lcaron"] = 318,
- ["Lmidot"] = 319,
- ["lmidot"] = 320,
- ["Lstrok"] = 321,
- ["lstrok"] = 322,
- ["Nacute"] = 323,
- ["nacute"] = 324,
- ["Ncedil"] = 325,
- ["ncedil"] = 326,
- ["Ncaron"] = 327,
- ["ncaron"] = 328,
- ["napos"] = 329,
- ["ENG"] = 330,
- ["eng"] = 331,
- ["Omacr"] = 332,
- ["omacr"] = 333,
- ["Odblac"] = 336,
- ["odblac"] = 337,
- ["OElig"] = 338,
- ["oelig"] = 339,
- ["Racute"] = 340,
- ["racute"] = 341,
- ["Rcedil"] = 342,
- ["rcedil"] = 343,
- ["Rcaron"] = 344,
- ["rcaron"] = 345,
- ["Sacute"] = 346,
- ["sacute"] = 347,
- ["Scirc"] = 348,
- ["scirc"] = 349,
- ["Scedil"] = 350,
- ["scedil"] = 351,
- ["Scaron"] = 352,
- ["scaron"] = 353,
- ["Tcedil"] = 354,
- ["tcedil"] = 355,
- ["Tcaron"] = 356,
- ["tcaron"] = 357,
- ["Tstrok"] = 358,
- ["tstrok"] = 359,
- ["Utilde"] = 360,
- ["utilde"] = 361,
- ["Umacr"] = 362,
- ["umacr"] = 363,
- ["Ubreve"] = 364,
- ["ubreve"] = 365,
- ["Uring"] = 366,
- ["uring"] = 367,
- ["Udblac"] = 368,
- ["udblac"] = 369,
- ["Uogon"] = 370,
- ["uogon"] = 371,
- ["Wcirc"] = 372,
- ["wcirc"] = 373,
- ["Ycirc"] = 374,
- ["ycirc"] = 375,
- ["Yuml"] = 376,
- ["Zacute"] = 377,
- ["zacute"] = 378,
- ["Zdot"] = 379,
- ["zdot"] = 380,
- ["Zcaron"] = 381,
- ["zcaron"] = 382,
- ["fnof"] = 402,
- ["imped"] = 437,
- ["gacute"] = 501,
- ["jmath"] = 567,
- ["circ"] = 710,
- ["Hacek"] = 711,
- ["caron"] = 711,
- ["Breve"] = 728,
- ["breve"] = 728,
- ["DiacriticalDot"] = 729,
- ["dot"] = 729,
- ["ring"] = 730,
- ["ogon"] = 731,
- ["DiacriticalTilde"] = 732,
- ["tilde"] = 732,
- ["DiacriticalDoubleAcute"] = 733,
- ["dblac"] = 733,
- ["DownBreve"] = 785,
- ["Alpha"] = 913,
- ["Beta"] = 914,
- ["Gamma"] = 915,
- ["Delta"] = 916,
- ["Epsilon"] = 917,
- ["Zeta"] = 918,
- ["Eta"] = 919,
- ["Theta"] = 920,
- ["Iota"] = 921,
- ["Kappa"] = 922,
- ["Lambda"] = 923,
- ["Mu"] = 924,
- ["Nu"] = 925,
- ["Xi"] = 926,
- ["Omicron"] = 927,
- ["Pi"] = 928,
- ["Rho"] = 929,
- ["Sigma"] = 931,
- ["Tau"] = 932,
- ["Upsilon"] = 933,
- ["Phi"] = 934,
- ["Chi"] = 935,
- ["Psi"] = 936,
- ["Omega"] = 937,
- ["ohm"] = 937,
- ["alpha"] = 945,
- ["beta"] = 946,
- ["gamma"] = 947,
- ["delta"] = 948,
- ["epsi"] = 949,
- ["epsilon"] = 949,
- ["zeta"] = 950,
- ["eta"] = 951,
- ["theta"] = 952,
- ["iota"] = 953,
- ["kappa"] = 954,
- ["lambda"] = 955,
- ["mu"] = 956,
- ["nu"] = 957,
- ["xi"] = 958,
- ["omicron"] = 959,
- ["pi"] = 960,
- ["rho"] = 961,
- ["sigmaf"] = 962,
- ["sigmav"] = 962,
- ["varsigma"] = 962,
- ["sigma"] = 963,
- ["tau"] = 964,
- ["upsi"] = 965,
- ["upsilon"] = 965,
- ["phi"] = 966,
- ["chi"] = 967,
- ["psi"] = 968,
- ["omega"] = 969,
- ["thetasym"] = 977,
- ["thetav"] = 977,
- ["vartheta"] = 977,
- ["Upsi"] = 978,
- ["upsih"] = 978,
- ["phiv"] = 981,
- ["straightphi"] = 981,
- ["varphi"] = 981,
- ["piv"] = 982,
- ["varpi"] = 982,
- ["Gammad"] = 988,
- ["digamma"] = 989,
- ["gammad"] = 989,
- ["kappav"] = 1008,
- ["varkappa"] = 1008,
- ["rhov"] = 1009,
- ["varrho"] = 1009,
- ["epsiv"] = 1013,
- ["straightepsilon"] = 1013,
- ["varepsilon"] = 1013,
- ["backepsilon"] = 1014,
- ["bepsi"] = 1014,
- ["IOcy"] = 1025,
- ["DJcy"] = 1026,
- ["GJcy"] = 1027,
- ["Jukcy"] = 1028,
- ["DScy"] = 1029,
- ["Iukcy"] = 1030,
- ["YIcy"] = 1031,
- ["Jsercy"] = 1032,
- ["LJcy"] = 1033,
- ["NJcy"] = 1034,
- ["TSHcy"] = 1035,
- ["KJcy"] = 1036,
- ["Ubrcy"] = 1038,
- ["DZcy"] = 1039,
- ["Acy"] = 1040,
- ["Bcy"] = 1041,
- ["Vcy"] = 1042,
- ["Gcy"] = 1043,
- ["Dcy"] = 1044,
- ["IEcy"] = 1045,
- ["ZHcy"] = 1046,
- ["Zcy"] = 1047,
- ["Icy"] = 1048,
- ["Jcy"] = 1049,
- ["Kcy"] = 1050,
- ["Lcy"] = 1051,
- ["Mcy"] = 1052,
- ["Ncy"] = 1053,
- ["Ocy"] = 1054,
- ["Pcy"] = 1055,
- ["Rcy"] = 1056,
- ["Scy"] = 1057,
- ["Tcy"] = 1058,
- ["Ucy"] = 1059,
- ["Fcy"] = 1060,
- ["KHcy"] = 1061,
- ["TScy"] = 1062,
- ["CHcy"] = 1063,
- ["SHcy"] = 1064,
- ["SHCHcy"] = 1065,
- ["HARDcy"] = 1066,
- ["Ycy"] = 1067,
- ["SOFTcy"] = 1068,
- ["Ecy"] = 1069,
- ["YUcy"] = 1070,
- ["YAcy"] = 1071,
- ["acy"] = 1072,
- ["bcy"] = 1073,
- ["vcy"] = 1074,
- ["gcy"] = 1075,
- ["dcy"] = 1076,
- ["iecy"] = 1077,
- ["zhcy"] = 1078,
- ["zcy"] = 1079,
- ["icy"] = 1080,
- ["jcy"] = 1081,
- ["kcy"] = 1082,
- ["lcy"] = 1083,
- ["mcy"] = 1084,
- ["ncy"] = 1085,
- ["ocy"] = 1086,
- ["pcy"] = 1087,
- ["rcy"] = 1088,
- ["scy"] = 1089,
- ["tcy"] = 1090,
- ["ucy"] = 1091,
- ["fcy"] = 1092,
- ["khcy"] = 1093,
- ["tscy"] = 1094,
- ["chcy"] = 1095,
- ["shcy"] = 1096,
- ["shchcy"] = 1097,
- ["hardcy"] = 1098,
- ["ycy"] = 1099,
- ["softcy"] = 1100,
- ["ecy"] = 1101,
- ["yucy"] = 1102,
- ["yacy"] = 1103,
- ["iocy"] = 1105,
- ["djcy"] = 1106,
- ["gjcy"] = 1107,
- ["jukcy"] = 1108,
- ["dscy"] = 1109,
- ["iukcy"] = 1110,
- ["yicy"] = 1111,
- ["jsercy"] = 1112,
- ["ljcy"] = 1113,
- ["njcy"] = 1114,
- ["tshcy"] = 1115,
- ["kjcy"] = 1116,
- ["ubrcy"] = 1118,
- ["dzcy"] = 1119,
- ["ensp"] = 8194,
- ["emsp"] = 8195,
- ["emsp13"] = 8196,
- ["emsp14"] = 8197,
- ["numsp"] = 8199,
- ["puncsp"] = 8200,
- ["ThinSpace"] = 8201,
- ["thinsp"] = 8201,
- ["VeryThinSpace"] = 8202,
- ["hairsp"] = 8202,
- ["NegativeMediumSpace"] = 8203,
- ["NegativeThickSpace"] = 8203,
- ["NegativeThinSpace"] = 8203,
- ["NegativeVeryThinSpace"] = 8203,
- ["ZeroWidthSpace"] = 8203,
- ["zwnj"] = 8204,
- ["zwj"] = 8205,
- ["lrm"] = 8206,
- ["rlm"] = 8207,
- ["dash"] = 8208,
- ["hyphen"] = 8208,
- ["ndash"] = 8211,
- ["mdash"] = 8212,
- ["horbar"] = 8213,
- ["Verbar"] = 8214,
- ["Vert"] = 8214,
- ["OpenCurlyQuote"] = 8216,
- ["lsquo"] = 8216,
- ["CloseCurlyQuote"] = 8217,
- ["rsquo"] = 8217,
- ["rsquor"] = 8217,
- ["lsquor"] = 8218,
- ["sbquo"] = 8218,
- ["OpenCurlyDoubleQuote"] = 8220,
- ["ldquo"] = 8220,
- ["CloseCurlyDoubleQuote"] = 8221,
- ["rdquo"] = 8221,
- ["rdquor"] = 8221,
- ["bdquo"] = 8222,
- ["ldquor"] = 8222,
- ["dagger"] = 8224,
- ["Dagger"] = 8225,
- ["ddagger"] = 8225,
- ["bull"] = 8226,
- ["bullet"] = 8226,
- ["nldr"] = 8229,
- ["hellip"] = 8230,
- ["mldr"] = 8230,
- ["permil"] = 8240,
- ["pertenk"] = 8241,
- ["prime"] = 8242,
- ["Prime"] = 8243,
- ["tprime"] = 8244,
- ["backprime"] = 8245,
- ["bprime"] = 8245,
- ["lsaquo"] = 8249,
- ["rsaquo"] = 8250,
- ["OverBar"] = 8254,
- ["oline"] = 8254,
- ["caret"] = 8257,
- ["hybull"] = 8259,
- ["frasl"] = 8260,
- ["bsemi"] = 8271,
- ["qprime"] = 8279,
- ["MediumSpace"] = 8287,
- ["ThickSpace"] = {8287, 8202},
- ["NoBreak"] = 8288,
- ["ApplyFunction"] = 8289,
- ["af"] = 8289,
- ["InvisibleTimes"] = 8290,
- ["it"] = 8290,
- ["InvisibleComma"] = 8291,
- ["ic"] = 8291,
- ["euro"] = 8364,
- ["TripleDot"] = 8411,
- ["tdot"] = 8411,
- ["DotDot"] = 8412,
- ["Copf"] = 8450,
- ["complexes"] = 8450,
- ["incare"] = 8453,
- ["gscr"] = 8458,
- ["HilbertSpace"] = 8459,
- ["Hscr"] = 8459,
- ["hamilt"] = 8459,
- ["Hfr"] = 8460,
- ["Poincareplane"] = 8460,
- ["Hopf"] = 8461,
- ["quaternions"] = 8461,
- ["planckh"] = 8462,
- ["hbar"] = 8463,
- ["hslash"] = 8463,
- ["planck"] = 8463,
- ["plankv"] = 8463,
- ["Iscr"] = 8464,
- ["imagline"] = 8464,
- ["Ifr"] = 8465,
- ["Im"] = 8465,
- ["image"] = 8465,
- ["imagpart"] = 8465,
- ["Laplacetrf"] = 8466,
- ["Lscr"] = 8466,
- ["lagran"] = 8466,
- ["ell"] = 8467,
- ["Nopf"] = 8469,
- ["naturals"] = 8469,
- ["numero"] = 8470,
- ["copysr"] = 8471,
- ["weierp"] = 8472,
- ["wp"] = 8472,
- ["Popf"] = 8473,
- ["primes"] = 8473,
- ["Qopf"] = 8474,
- ["rationals"] = 8474,
- ["Rscr"] = 8475,
- ["realine"] = 8475,
- ["Re"] = 8476,
- ["Rfr"] = 8476,
- ["real"] = 8476,
- ["realpart"] = 8476,
- ["Ropf"] = 8477,
- ["reals"] = 8477,
- ["rx"] = 8478,
- ["TRADE"] = 8482,
- ["trade"] = 8482,
- ["Zopf"] = 8484,
- ["integers"] = 8484,
- ["mho"] = 8487,
- ["Zfr"] = 8488,
- ["zeetrf"] = 8488,
- ["iiota"] = 8489,
- ["Bernoullis"] = 8492,
- ["Bscr"] = 8492,
- ["bernou"] = 8492,
- ["Cayleys"] = 8493,
- ["Cfr"] = 8493,
- ["escr"] = 8495,
- ["Escr"] = 8496,
- ["expectation"] = 8496,
- ["Fouriertrf"] = 8497,
- ["Fscr"] = 8497,
- ["Mellintrf"] = 8499,
- ["Mscr"] = 8499,
- ["phmmat"] = 8499,
- ["order"] = 8500,
- ["orderof"] = 8500,
- ["oscr"] = 8500,
- ["alefsym"] = 8501,
- ["aleph"] = 8501,
- ["beth"] = 8502,
- ["gimel"] = 8503,
- ["daleth"] = 8504,
- ["CapitalDifferentialD"] = 8517,
- ["DD"] = 8517,
- ["DifferentialD"] = 8518,
- ["dd"] = 8518,
- ["ExponentialE"] = 8519,
- ["ee"] = 8519,
- ["exponentiale"] = 8519,
- ["ImaginaryI"] = 8520,
- ["ii"] = 8520,
- ["frac13"] = 8531,
- ["frac23"] = 8532,
- ["frac15"] = 8533,
- ["frac25"] = 8534,
- ["frac35"] = 8535,
- ["frac45"] = 8536,
- ["frac16"] = 8537,
- ["frac56"] = 8538,
- ["frac18"] = 8539,
- ["frac38"] = 8540,
- ["frac58"] = 8541,
- ["frac78"] = 8542,
- ["LeftArrow"] = 8592,
- ["ShortLeftArrow"] = 8592,
- ["larr"] = 8592,
- ["leftarrow"] = 8592,
- ["slarr"] = 8592,
- ["ShortUpArrow"] = 8593,
- ["UpArrow"] = 8593,
- ["uarr"] = 8593,
- ["uparrow"] = 8593,
- ["RightArrow"] = 8594,
- ["ShortRightArrow"] = 8594,
- ["rarr"] = 8594,
- ["rightarrow"] = 8594,
- ["srarr"] = 8594,
- ["DownArrow"] = 8595,
- ["ShortDownArrow"] = 8595,
- ["darr"] = 8595,
- ["downarrow"] = 8595,
- ["LeftRightArrow"] = 8596,
- ["harr"] = 8596,
- ["leftrightarrow"] = 8596,
- ["UpDownArrow"] = 8597,
- ["updownarrow"] = 8597,
- ["varr"] = 8597,
- ["UpperLeftArrow"] = 8598,
- ["nwarr"] = 8598,
- ["nwarrow"] = 8598,
- ["UpperRightArrow"] = 8599,
- ["nearr"] = 8599,
- ["nearrow"] = 8599,
- ["LowerRightArrow"] = 8600,
- ["searr"] = 8600,
- ["searrow"] = 8600,
- ["LowerLeftArrow"] = 8601,
- ["swarr"] = 8601,
- ["swarrow"] = 8601,
- ["nlarr"] = 8602,
- ["nleftarrow"] = 8602,
- ["nrarr"] = 8603,
- ["nrightarrow"] = 8603,
- ["nrarrw"] = {8605, 824},
- ["rarrw"] = 8605,
- ["rightsquigarrow"] = 8605,
- ["Larr"] = 8606,
- ["twoheadleftarrow"] = 8606,
- ["Uarr"] = 8607,
- ["Rarr"] = 8608,
- ["twoheadrightarrow"] = 8608,
- ["Darr"] = 8609,
- ["larrtl"] = 8610,
- ["leftarrowtail"] = 8610,
- ["rarrtl"] = 8611,
- ["rightarrowtail"] = 8611,
- ["LeftTeeArrow"] = 8612,
- ["mapstoleft"] = 8612,
- ["UpTeeArrow"] = 8613,
- ["mapstoup"] = 8613,
- ["RightTeeArrow"] = 8614,
- ["map"] = 8614,
- ["mapsto"] = 8614,
- ["DownTeeArrow"] = 8615,
- ["mapstodown"] = 8615,
- ["hookleftarrow"] = 8617,
- ["larrhk"] = 8617,
- ["hookrightarrow"] = 8618,
- ["rarrhk"] = 8618,
- ["larrlp"] = 8619,
- ["looparrowleft"] = 8619,
- ["looparrowright"] = 8620,
- ["rarrlp"] = 8620,
- ["harrw"] = 8621,
- ["leftrightsquigarrow"] = 8621,
- ["nharr"] = 8622,
- ["nleftrightarrow"] = 8622,
- ["Lsh"] = 8624,
- ["lsh"] = 8624,
- ["Rsh"] = 8625,
- ["rsh"] = 8625,
- ["ldsh"] = 8626,
- ["rdsh"] = 8627,
- ["crarr"] = 8629,
- ["cularr"] = 8630,
- ["curvearrowleft"] = 8630,
- ["curarr"] = 8631,
- ["curvearrowright"] = 8631,
- ["circlearrowleft"] = 8634,
- ["olarr"] = 8634,
- ["circlearrowright"] = 8635,
- ["orarr"] = 8635,
- ["LeftVector"] = 8636,
- ["leftharpoonup"] = 8636,
- ["lharu"] = 8636,
- ["DownLeftVector"] = 8637,
- ["leftharpoondown"] = 8637,
- ["lhard"] = 8637,
- ["RightUpVector"] = 8638,
- ["uharr"] = 8638,
- ["upharpoonright"] = 8638,
- ["LeftUpVector"] = 8639,
- ["uharl"] = 8639,
- ["upharpoonleft"] = 8639,
- ["RightVector"] = 8640,
- ["rharu"] = 8640,
- ["rightharpoonup"] = 8640,
- ["DownRightVector"] = 8641,
- ["rhard"] = 8641,
- ["rightharpoondown"] = 8641,
- ["RightDownVector"] = 8642,
- ["dharr"] = 8642,
- ["downharpoonright"] = 8642,
- ["LeftDownVector"] = 8643,
- ["dharl"] = 8643,
- ["downharpoonleft"] = 8643,
- ["RightArrowLeftArrow"] = 8644,
- ["rightleftarrows"] = 8644,
- ["rlarr"] = 8644,
- ["UpArrowDownArrow"] = 8645,
- ["udarr"] = 8645,
- ["LeftArrowRightArrow"] = 8646,
- ["leftrightarrows"] = 8646,
- ["lrarr"] = 8646,
- ["leftleftarrows"] = 8647,
- ["llarr"] = 8647,
- ["upuparrows"] = 8648,
- ["uuarr"] = 8648,
- ["rightrightarrows"] = 8649,
- ["rrarr"] = 8649,
- ["ddarr"] = 8650,
- ["downdownarrows"] = 8650,
- ["ReverseEquilibrium"] = 8651,
- ["leftrightharpoons"] = 8651,
- ["lrhar"] = 8651,
- ["Equilibrium"] = 8652,
- ["rightleftharpoons"] = 8652,
- ["rlhar"] = 8652,
- ["nLeftarrow"] = 8653,
- ["nlArr"] = 8653,
- ["nLeftrightarrow"] = 8654,
- ["nhArr"] = 8654,
- ["nRightarrow"] = 8655,
- ["nrArr"] = 8655,
- ["DoubleLeftArrow"] = 8656,
- ["Leftarrow"] = 8656,
- ["lArr"] = 8656,
- ["DoubleUpArrow"] = 8657,
- ["Uparrow"] = 8657,
- ["uArr"] = 8657,
- ["DoubleRightArrow"] = 8658,
- ["Implies"] = 8658,
- ["Rightarrow"] = 8658,
- ["rArr"] = 8658,
- ["DoubleDownArrow"] = 8659,
- ["Downarrow"] = 8659,
- ["dArr"] = 8659,
- ["DoubleLeftRightArrow"] = 8660,
- ["Leftrightarrow"] = 8660,
- ["hArr"] = 8660,
- ["iff"] = 8660,
- ["DoubleUpDownArrow"] = 8661,
- ["Updownarrow"] = 8661,
- ["vArr"] = 8661,
- ["nwArr"] = 8662,
- ["neArr"] = 8663,
- ["seArr"] = 8664,
- ["swArr"] = 8665,
- ["Lleftarrow"] = 8666,
- ["lAarr"] = 8666,
- ["Rrightarrow"] = 8667,
- ["rAarr"] = 8667,
- ["zigrarr"] = 8669,
- ["LeftArrowBar"] = 8676,
- ["larrb"] = 8676,
- ["RightArrowBar"] = 8677,
- ["rarrb"] = 8677,
- ["DownArrowUpArrow"] = 8693,
- ["duarr"] = 8693,
- ["loarr"] = 8701,
- ["roarr"] = 8702,
- ["hoarr"] = 8703,
- ["ForAll"] = 8704,
- ["forall"] = 8704,
- ["comp"] = 8705,
- ["complement"] = 8705,
- ["PartialD"] = 8706,
- ["npart"] = {8706, 824},
- ["part"] = 8706,
- ["Exists"] = 8707,
- ["exist"] = 8707,
- ["NotExists"] = 8708,
- ["nexist"] = 8708,
- ["nexists"] = 8708,
- ["empty"] = 8709,
- ["emptyset"] = 8709,
- ["emptyv"] = 8709,
- ["varnothing"] = 8709,
- ["Del"] = 8711,
- ["nabla"] = 8711,
- ["Element"] = 8712,
- ["in"] = 8712,
- ["isin"] = 8712,
- ["isinv"] = 8712,
- ["NotElement"] = 8713,
- ["notin"] = 8713,
- ["notinva"] = 8713,
- ["ReverseElement"] = 8715,
- ["SuchThat"] = 8715,
- ["ni"] = 8715,
- ["niv"] = 8715,
- ["NotReverseElement"] = 8716,
- ["notni"] = 8716,
- ["notniva"] = 8716,
- ["Product"] = 8719,
- ["prod"] = 8719,
- ["Coproduct"] = 8720,
- ["coprod"] = 8720,
- ["Sum"] = 8721,
- ["sum"] = 8721,
- ["minus"] = 8722,
- ["MinusPlus"] = 8723,
- ["mnplus"] = 8723,
- ["mp"] = 8723,
- ["dotplus"] = 8724,
- ["plusdo"] = 8724,
- ["Backslash"] = 8726,
- ["setminus"] = 8726,
- ["setmn"] = 8726,
- ["smallsetminus"] = 8726,
- ["ssetmn"] = 8726,
- ["lowast"] = 8727,
- ["SmallCircle"] = 8728,
- ["compfn"] = 8728,
- ["Sqrt"] = 8730,
- ["radic"] = 8730,
- ["Proportional"] = 8733,
- ["prop"] = 8733,
- ["propto"] = 8733,
- ["varpropto"] = 8733,
- ["vprop"] = 8733,
- ["infin"] = 8734,
- ["angrt"] = 8735,
- ["ang"] = 8736,
- ["angle"] = 8736,
- ["nang"] = {8736, 8402},
- ["angmsd"] = 8737,
- ["measuredangle"] = 8737,
- ["angsph"] = 8738,
- ["VerticalBar"] = 8739,
- ["mid"] = 8739,
- ["shortmid"] = 8739,
- ["smid"] = 8739,
- ["NotVerticalBar"] = 8740,
- ["nmid"] = 8740,
- ["nshortmid"] = 8740,
- ["nsmid"] = 8740,
- ["DoubleVerticalBar"] = 8741,
- ["par"] = 8741,
- ["parallel"] = 8741,
- ["shortparallel"] = 8741,
- ["spar"] = 8741,
- ["NotDoubleVerticalBar"] = 8742,
- ["npar"] = 8742,
- ["nparallel"] = 8742,
- ["nshortparallel"] = 8742,
- ["nspar"] = 8742,
- ["and"] = 8743,
- ["wedge"] = 8743,
- ["or"] = 8744,
- ["vee"] = 8744,
- ["cap"] = 8745,
- ["caps"] = {8745, 65024},
- ["cup"] = 8746,
- ["cups"] = {8746, 65024},
- ["Integral"] = 8747,
- ["int"] = 8747,
- ["Int"] = 8748,
- ["iiint"] = 8749,
- ["tint"] = 8749,
- ["ContourIntegral"] = 8750,
- ["conint"] = 8750,
- ["oint"] = 8750,
- ["Conint"] = 8751,
- ["DoubleContourIntegral"] = 8751,
- ["Cconint"] = 8752,
- ["cwint"] = 8753,
- ["ClockwiseContourIntegral"] = 8754,
- ["cwconint"] = 8754,
- ["CounterClockwiseContourIntegral"] = 8755,
- ["awconint"] = 8755,
- ["Therefore"] = 8756,
- ["there4"] = 8756,
- ["therefore"] = 8756,
- ["Because"] = 8757,
- ["becaus"] = 8757,
- ["because"] = 8757,
- ["ratio"] = 8758,
- ["Colon"] = 8759,
- ["Proportion"] = 8759,
- ["dotminus"] = 8760,
- ["minusd"] = 8760,
- ["mDDot"] = 8762,
- ["homtht"] = 8763,
- ["Tilde"] = 8764,
- ["nvsim"] = {8764, 8402},
- ["sim"] = 8764,
- ["thicksim"] = 8764,
- ["thksim"] = 8764,
- ["backsim"] = 8765,
- ["bsim"] = 8765,
- ["race"] = {8765, 817},
- ["ac"] = 8766,
- ["acE"] = {8766, 819},
- ["mstpos"] = 8766,
- ["acd"] = 8767,
- ["VerticalTilde"] = 8768,
- ["wr"] = 8768,
- ["wreath"] = 8768,
- ["NotTilde"] = 8769,
- ["nsim"] = 8769,
- ["EqualTilde"] = 8770,
- ["NotEqualTilde"] = {8770, 824},
- ["eqsim"] = 8770,
- ["esim"] = 8770,
- ["nesim"] = {8770, 824},
- ["TildeEqual"] = 8771,
- ["sime"] = 8771,
- ["simeq"] = 8771,
- ["NotTildeEqual"] = 8772,
- ["nsime"] = 8772,
- ["nsimeq"] = 8772,
- ["TildeFullEqual"] = 8773,
- ["cong"] = 8773,
- ["simne"] = 8774,
- ["NotTildeFullEqual"] = 8775,
- ["ncong"] = 8775,
- ["TildeTilde"] = 8776,
- ["ap"] = 8776,
- ["approx"] = 8776,
- ["asymp"] = 8776,
- ["thickapprox"] = 8776,
- ["thkap"] = 8776,
- ["NotTildeTilde"] = 8777,
- ["nap"] = 8777,
- ["napprox"] = 8777,
- ["ape"] = 8778,
- ["approxeq"] = 8778,
- ["apid"] = 8779,
- ["napid"] = {8779, 824},
- ["backcong"] = 8780,
- ["bcong"] = 8780,
- ["CupCap"] = 8781,
- ["asympeq"] = 8781,
- ["nvap"] = {8781, 8402},
- ["Bumpeq"] = 8782,
- ["HumpDownHump"] = 8782,
- ["NotHumpDownHump"] = {8782, 824},
- ["bump"] = 8782,
- ["nbump"] = {8782, 824},
- ["HumpEqual"] = 8783,
- ["NotHumpEqual"] = {8783, 824},
- ["bumpe"] = 8783,
- ["bumpeq"] = 8783,
- ["nbumpe"] = {8783, 824},
- ["DotEqual"] = 8784,
- ["doteq"] = 8784,
- ["esdot"] = 8784,
- ["nedot"] = {8784, 824},
- ["doteqdot"] = 8785,
- ["eDot"] = 8785,
- ["efDot"] = 8786,
- ["fallingdotseq"] = 8786,
- ["erDot"] = 8787,
- ["risingdotseq"] = 8787,
- ["Assign"] = 8788,
- ["colone"] = 8788,
- ["coloneq"] = 8788,
- ["ecolon"] = 8789,
- ["eqcolon"] = 8789,
- ["ecir"] = 8790,
- ["eqcirc"] = 8790,
- ["circeq"] = 8791,
- ["cire"] = 8791,
- ["wedgeq"] = 8793,
- ["veeeq"] = 8794,
- ["triangleq"] = 8796,
- ["trie"] = 8796,
- ["equest"] = 8799,
- ["questeq"] = 8799,
- ["NotEqual"] = 8800,
- ["ne"] = 8800,
- ["Congruent"] = 8801,
- ["bnequiv"] = {8801, 8421},
- ["equiv"] = 8801,
- ["NotCongruent"] = 8802,
- ["nequiv"] = 8802,
- ["le"] = 8804,
- ["leq"] = 8804,
- ["nvle"] = {8804, 8402},
- ["GreaterEqual"] = 8805,
- ["ge"] = 8805,
- ["geq"] = 8805,
- ["nvge"] = {8805, 8402},
- ["LessFullEqual"] = 8806,
- ["lE"] = 8806,
- ["leqq"] = 8806,
- ["nlE"] = {8806, 824},
- ["nleqq"] = {8806, 824},
- ["GreaterFullEqual"] = 8807,
- ["NotGreaterFullEqual"] = {8807, 824},
- ["gE"] = 8807,
- ["geqq"] = 8807,
- ["ngE"] = {8807, 824},
- ["ngeqq"] = {8807, 824},
- ["lnE"] = 8808,
- ["lneqq"] = 8808,
- ["lvertneqq"] = {8808, 65024},
- ["lvnE"] = {8808, 65024},
- ["gnE"] = 8809,
- ["gneqq"] = 8809,
- ["gvertneqq"] = {8809, 65024},
- ["gvnE"] = {8809, 65024},
- ["Lt"] = 8810,
- ["NestedLessLess"] = 8810,
- ["NotLessLess"] = {8810, 824},
- ["ll"] = 8810,
- ["nLt"] = {8810, 8402},
- ["nLtv"] = {8810, 824},
- ["Gt"] = 8811,
- ["NestedGreaterGreater"] = 8811,
- ["NotGreaterGreater"] = {8811, 824},
- ["gg"] = 8811,
- ["nGt"] = {8811, 8402},
- ["nGtv"] = {8811, 824},
- ["between"] = 8812,
- ["twixt"] = 8812,
- ["NotCupCap"] = 8813,
- ["NotLess"] = 8814,
- ["nless"] = 8814,
- ["nlt"] = 8814,
- ["NotGreater"] = 8815,
- ["ngt"] = 8815,
- ["ngtr"] = 8815,
- ["NotLessEqual"] = 8816,
- ["nle"] = 8816,
- ["nleq"] = 8816,
- ["NotGreaterEqual"] = 8817,
- ["nge"] = 8817,
- ["ngeq"] = 8817,
- ["LessTilde"] = 8818,
- ["lesssim"] = 8818,
- ["lsim"] = 8818,
- ["GreaterTilde"] = 8819,
- ["gsim"] = 8819,
- ["gtrsim"] = 8819,
- ["NotLessTilde"] = 8820,
- ["nlsim"] = 8820,
- ["NotGreaterTilde"] = 8821,
- ["ngsim"] = 8821,
- ["LessGreater"] = 8822,
- ["lessgtr"] = 8822,
- ["lg"] = 8822,
- ["GreaterLess"] = 8823,
- ["gl"] = 8823,
- ["gtrless"] = 8823,
- ["NotLessGreater"] = 8824,
- ["ntlg"] = 8824,
- ["NotGreaterLess"] = 8825,
- ["ntgl"] = 8825,
- ["Precedes"] = 8826,
- ["pr"] = 8826,
- ["prec"] = 8826,
- ["Succeeds"] = 8827,
- ["sc"] = 8827,
- ["succ"] = 8827,
- ["PrecedesSlantEqual"] = 8828,
- ["prcue"] = 8828,
- ["preccurlyeq"] = 8828,
- ["SucceedsSlantEqual"] = 8829,
- ["sccue"] = 8829,
- ["succcurlyeq"] = 8829,
- ["PrecedesTilde"] = 8830,
- ["precsim"] = 8830,
- ["prsim"] = 8830,
- ["NotSucceedsTilde"] = {8831, 824},
- ["SucceedsTilde"] = 8831,
- ["scsim"] = 8831,
- ["succsim"] = 8831,
- ["NotPrecedes"] = 8832,
- ["npr"] = 8832,
- ["nprec"] = 8832,
- ["NotSucceeds"] = 8833,
- ["nsc"] = 8833,
- ["nsucc"] = 8833,
- ["NotSubset"] = {8834, 8402},
- ["nsubset"] = {8834, 8402},
- ["sub"] = 8834,
- ["subset"] = 8834,
- ["vnsub"] = {8834, 8402},
- ["NotSuperset"] = {8835, 8402},
- ["Superset"] = 8835,
- ["nsupset"] = {8835, 8402},
- ["sup"] = 8835,
- ["supset"] = 8835,
- ["vnsup"] = {8835, 8402},
- ["nsub"] = 8836,
- ["nsup"] = 8837,
- ["SubsetEqual"] = 8838,
- ["sube"] = 8838,
- ["subseteq"] = 8838,
- ["SupersetEqual"] = 8839,
- ["supe"] = 8839,
- ["supseteq"] = 8839,
- ["NotSubsetEqual"] = 8840,
- ["nsube"] = 8840,
- ["nsubseteq"] = 8840,
- ["NotSupersetEqual"] = 8841,
- ["nsupe"] = 8841,
- ["nsupseteq"] = 8841,
- ["subne"] = 8842,
- ["subsetneq"] = 8842,
- ["varsubsetneq"] = {8842, 65024},
- ["vsubne"] = {8842, 65024},
- ["supne"] = 8843,
- ["supsetneq"] = 8843,
- ["varsupsetneq"] = {8843, 65024},
- ["vsupne"] = {8843, 65024},
- ["cupdot"] = 8845,
- ["UnionPlus"] = 8846,
- ["uplus"] = 8846,
- ["NotSquareSubset"] = {8847, 824},
- ["SquareSubset"] = 8847,
- ["sqsub"] = 8847,
- ["sqsubset"] = 8847,
- ["NotSquareSuperset"] = {8848, 824},
- ["SquareSuperset"] = 8848,
- ["sqsup"] = 8848,
- ["sqsupset"] = 8848,
- ["SquareSubsetEqual"] = 8849,
- ["sqsube"] = 8849,
- ["sqsubseteq"] = 8849,
- ["SquareSupersetEqual"] = 8850,
- ["sqsupe"] = 8850,
- ["sqsupseteq"] = 8850,
- ["SquareIntersection"] = 8851,
- ["sqcap"] = 8851,
- ["sqcaps"] = {8851, 65024},
- ["SquareUnion"] = 8852,
- ["sqcup"] = 8852,
- ["sqcups"] = {8852, 65024},
- ["CirclePlus"] = 8853,
- ["oplus"] = 8853,
- ["CircleMinus"] = 8854,
- ["ominus"] = 8854,
- ["CircleTimes"] = 8855,
- ["otimes"] = 8855,
- ["osol"] = 8856,
- ["CircleDot"] = 8857,
- ["odot"] = 8857,
- ["circledcirc"] = 8858,
- ["ocir"] = 8858,
- ["circledast"] = 8859,
- ["oast"] = 8859,
- ["circleddash"] = 8861,
- ["odash"] = 8861,
- ["boxplus"] = 8862,
- ["plusb"] = 8862,
- ["boxminus"] = 8863,
- ["minusb"] = 8863,
- ["boxtimes"] = 8864,
- ["timesb"] = 8864,
- ["dotsquare"] = 8865,
- ["sdotb"] = 8865,
- ["RightTee"] = 8866,
- ["vdash"] = 8866,
- ["LeftTee"] = 8867,
- ["dashv"] = 8867,
- ["DownTee"] = 8868,
- ["top"] = 8868,
- ["UpTee"] = 8869,
- ["bot"] = 8869,
- ["bottom"] = 8869,
- ["perp"] = 8869,
- ["models"] = 8871,
- ["DoubleRightTee"] = 8872,
- ["vDash"] = 8872,
- ["Vdash"] = 8873,
- ["Vvdash"] = 8874,
- ["VDash"] = 8875,
- ["nvdash"] = 8876,
- ["nvDash"] = 8877,
- ["nVdash"] = 8878,
- ["nVDash"] = 8879,
- ["prurel"] = 8880,
- ["LeftTriangle"] = 8882,
- ["vartriangleleft"] = 8882,
- ["vltri"] = 8882,
- ["RightTriangle"] = 8883,
- ["vartriangleright"] = 8883,
- ["vrtri"] = 8883,
- ["LeftTriangleEqual"] = 8884,
- ["ltrie"] = 8884,
- ["nvltrie"] = {8884, 8402},
- ["trianglelefteq"] = 8884,
- ["RightTriangleEqual"] = 8885,
- ["nvrtrie"] = {8885, 8402},
- ["rtrie"] = 8885,
- ["trianglerighteq"] = 8885,
- ["origof"] = 8886,
- ["imof"] = 8887,
- ["multimap"] = 8888,
- ["mumap"] = 8888,
- ["hercon"] = 8889,
- ["intcal"] = 8890,
- ["intercal"] = 8890,
- ["veebar"] = 8891,
- ["barvee"] = 8893,
- ["angrtvb"] = 8894,
- ["lrtri"] = 8895,
- ["Wedge"] = 8896,
- ["bigwedge"] = 8896,
- ["xwedge"] = 8896,
- ["Vee"] = 8897,
- ["bigvee"] = 8897,
- ["xvee"] = 8897,
- ["Intersection"] = 8898,
- ["bigcap"] = 8898,
- ["xcap"] = 8898,
- ["Union"] = 8899,
- ["bigcup"] = 8899,
- ["xcup"] = 8899,
- ["Diamond"] = 8900,
- ["diam"] = 8900,
- ["diamond"] = 8900,
- ["sdot"] = 8901,
- ["Star"] = 8902,
- ["sstarf"] = 8902,
- ["divideontimes"] = 8903,
- ["divonx"] = 8903,
- ["bowtie"] = 8904,
- ["ltimes"] = 8905,
- ["rtimes"] = 8906,
- ["leftthreetimes"] = 8907,
- ["lthree"] = 8907,
- ["rightthreetimes"] = 8908,
- ["rthree"] = 8908,
- ["backsimeq"] = 8909,
- ["bsime"] = 8909,
- ["curlyvee"] = 8910,
- ["cuvee"] = 8910,
- ["curlywedge"] = 8911,
- ["cuwed"] = 8911,
- ["Sub"] = 8912,
- ["Subset"] = 8912,
- ["Sup"] = 8913,
- ["Supset"] = 8913,
- ["Cap"] = 8914,
- ["Cup"] = 8915,
- ["fork"] = 8916,
- ["pitchfork"] = 8916,
- ["epar"] = 8917,
- ["lessdot"] = 8918,
- ["ltdot"] = 8918,
- ["gtdot"] = 8919,
- ["gtrdot"] = 8919,
- ["Ll"] = 8920,
- ["nLl"] = {8920, 824},
- ["Gg"] = 8921,
- ["ggg"] = 8921,
- ["nGg"] = {8921, 824},
- ["LessEqualGreater"] = 8922,
- ["leg"] = 8922,
- ["lesg"] = {8922, 65024},
- ["lesseqgtr"] = 8922,
- ["GreaterEqualLess"] = 8923,
- ["gel"] = 8923,
- ["gesl"] = {8923, 65024},
- ["gtreqless"] = 8923,
- ["cuepr"] = 8926,
- ["curlyeqprec"] = 8926,
- ["cuesc"] = 8927,
- ["curlyeqsucc"] = 8927,
- ["NotPrecedesSlantEqual"] = 8928,
- ["nprcue"] = 8928,
- ["NotSucceedsSlantEqual"] = 8929,
- ["nsccue"] = 8929,
- ["NotSquareSubsetEqual"] = 8930,
- ["nsqsube"] = 8930,
- ["NotSquareSupersetEqual"] = 8931,
- ["nsqsupe"] = 8931,
- ["lnsim"] = 8934,
- ["gnsim"] = 8935,
- ["precnsim"] = 8936,
- ["prnsim"] = 8936,
- ["scnsim"] = 8937,
- ["succnsim"] = 8937,
- ["NotLeftTriangle"] = 8938,
- ["nltri"] = 8938,
- ["ntriangleleft"] = 8938,
- ["NotRightTriangle"] = 8939,
- ["nrtri"] = 8939,
- ["ntriangleright"] = 8939,
- ["NotLeftTriangleEqual"] = 8940,
- ["nltrie"] = 8940,
- ["ntrianglelefteq"] = 8940,
- ["NotRightTriangleEqual"] = 8941,
- ["nrtrie"] = 8941,
- ["ntrianglerighteq"] = 8941,
- ["vellip"] = 8942,
- ["ctdot"] = 8943,
- ["utdot"] = 8944,
- ["dtdot"] = 8945,
- ["disin"] = 8946,
- ["isinsv"] = 8947,
- ["isins"] = 8948,
- ["isindot"] = 8949,
- ["notindot"] = {8949, 824},
- ["notinvc"] = 8950,
- ["notinvb"] = 8951,
- ["isinE"] = 8953,
- ["notinE"] = {8953, 824},
- ["nisd"] = 8954,
- ["xnis"] = 8955,
- ["nis"] = 8956,
- ["notnivc"] = 8957,
- ["notnivb"] = 8958,
- ["barwed"] = 8965,
- ["barwedge"] = 8965,
- ["Barwed"] = 8966,
- ["doublebarwedge"] = 8966,
- ["LeftCeiling"] = 8968,
- ["lceil"] = 8968,
- ["RightCeiling"] = 8969,
- ["rceil"] = 8969,
- ["LeftFloor"] = 8970,
- ["lfloor"] = 8970,
- ["RightFloor"] = 8971,
- ["rfloor"] = 8971,
- ["drcrop"] = 8972,
- ["dlcrop"] = 8973,
- ["urcrop"] = 8974,
- ["ulcrop"] = 8975,
- ["bnot"] = 8976,
- ["profline"] = 8978,
- ["profsurf"] = 8979,
- ["telrec"] = 8981,
- ["target"] = 8982,
- ["ulcorn"] = 8988,
- ["ulcorner"] = 8988,
- ["urcorn"] = 8989,
- ["urcorner"] = 8989,
- ["dlcorn"] = 8990,
- ["llcorner"] = 8990,
- ["drcorn"] = 8991,
- ["lrcorner"] = 8991,
- ["frown"] = 8994,
- ["sfrown"] = 8994,
- ["smile"] = 8995,
- ["ssmile"] = 8995,
- ["cylcty"] = 9005,
- ["profalar"] = 9006,
- ["topbot"] = 9014,
- ["ovbar"] = 9021,
- ["solbar"] = 9023,
- ["angzarr"] = 9084,
- ["lmoust"] = 9136,
- ["lmoustache"] = 9136,
- ["rmoust"] = 9137,
- ["rmoustache"] = 9137,
- ["OverBracket"] = 9140,
- ["tbrk"] = 9140,
- ["UnderBracket"] = 9141,
- ["bbrk"] = 9141,
- ["bbrktbrk"] = 9142,
- ["OverParenthesis"] = 9180,
- ["UnderParenthesis"] = 9181,
- ["OverBrace"] = 9182,
- ["UnderBrace"] = 9183,
- ["trpezium"] = 9186,
- ["elinters"] = 9191,
- ["blank"] = 9251,
- ["circledS"] = 9416,
- ["oS"] = 9416,
- ["HorizontalLine"] = 9472,
- ["boxh"] = 9472,
- ["boxv"] = 9474,
- ["boxdr"] = 9484,
- ["boxdl"] = 9488,
- ["boxur"] = 9492,
- ["boxul"] = 9496,
- ["boxvr"] = 9500,
- ["boxvl"] = 9508,
- ["boxhd"] = 9516,
- ["boxhu"] = 9524,
- ["boxvh"] = 9532,
- ["boxH"] = 9552,
- ["boxV"] = 9553,
- ["boxdR"] = 9554,
- ["boxDr"] = 9555,
- ["boxDR"] = 9556,
- ["boxdL"] = 9557,
- ["boxDl"] = 9558,
- ["boxDL"] = 9559,
- ["boxuR"] = 9560,
- ["boxUr"] = 9561,
- ["boxUR"] = 9562,
- ["boxuL"] = 9563,
- ["boxUl"] = 9564,
- ["boxUL"] = 9565,
- ["boxvR"] = 9566,
- ["boxVr"] = 9567,
- ["boxVR"] = 9568,
- ["boxvL"] = 9569,
- ["boxVl"] = 9570,
- ["boxVL"] = 9571,
- ["boxHd"] = 9572,
- ["boxhD"] = 9573,
- ["boxHD"] = 9574,
- ["boxHu"] = 9575,
- ["boxhU"] = 9576,
- ["boxHU"] = 9577,
- ["boxvH"] = 9578,
- ["boxVh"] = 9579,
- ["boxVH"] = 9580,
- ["uhblk"] = 9600,
- ["lhblk"] = 9604,
- ["block"] = 9608,
- ["blk14"] = 9617,
- ["blk12"] = 9618,
- ["blk34"] = 9619,
- ["Square"] = 9633,
- ["squ"] = 9633,
- ["square"] = 9633,
- ["FilledVerySmallSquare"] = 9642,
- ["blacksquare"] = 9642,
- ["squarf"] = 9642,
- ["squf"] = 9642,
- ["EmptyVerySmallSquare"] = 9643,
- ["rect"] = 9645,
- ["marker"] = 9646,
- ["fltns"] = 9649,
- ["bigtriangleup"] = 9651,
- ["xutri"] = 9651,
- ["blacktriangle"] = 9652,
- ["utrif"] = 9652,
- ["triangle"] = 9653,
- ["utri"] = 9653,
- ["blacktriangleright"] = 9656,
- ["rtrif"] = 9656,
- ["rtri"] = 9657,
- ["triangleright"] = 9657,
- ["bigtriangledown"] = 9661,
- ["xdtri"] = 9661,
- ["blacktriangledown"] = 9662,
- ["dtrif"] = 9662,
- ["dtri"] = 9663,
- ["triangledown"] = 9663,
- ["blacktriangleleft"] = 9666,
- ["ltrif"] = 9666,
- ["ltri"] = 9667,
- ["triangleleft"] = 9667,
- ["loz"] = 9674,
- ["lozenge"] = 9674,
- ["cir"] = 9675,
- ["tridot"] = 9708,
- ["bigcirc"] = 9711,
- ["xcirc"] = 9711,
- ["ultri"] = 9720,
- ["urtri"] = 9721,
- ["lltri"] = 9722,
- ["EmptySmallSquare"] = 9723,
- ["FilledSmallSquare"] = 9724,
- ["bigstar"] = 9733,
- ["starf"] = 9733,
- ["star"] = 9734,
- ["phone"] = 9742,
- ["female"] = 9792,
- ["male"] = 9794,
- ["spades"] = 9824,
- ["spadesuit"] = 9824,
- ["clubs"] = 9827,
- ["clubsuit"] = 9827,
- ["hearts"] = 9829,
- ["heartsuit"] = 9829,
- ["diamondsuit"] = 9830,
- ["diams"] = 9830,
- ["sung"] = 9834,
- ["flat"] = 9837,
- ["natur"] = 9838,
- ["natural"] = 9838,
- ["sharp"] = 9839,
- ["check"] = 10003,
- ["checkmark"] = 10003,
- ["cross"] = 10007,
- ["malt"] = 10016,
- ["maltese"] = 10016,
- ["sext"] = 10038,
- ["VerticalSeparator"] = 10072,
- ["lbbrk"] = 10098,
- ["rbbrk"] = 10099,
- ["bsolhsub"] = 10184,
- ["suphsol"] = 10185,
- ["LeftDoubleBracket"] = 10214,
- ["lobrk"] = 10214,
- ["RightDoubleBracket"] = 10215,
- ["robrk"] = 10215,
- ["LeftAngleBracket"] = 10216,
- ["lang"] = 10216,
- ["langle"] = 10216,
- ["RightAngleBracket"] = 10217,
- ["rang"] = 10217,
- ["rangle"] = 10217,
- ["Lang"] = 10218,
- ["Rang"] = 10219,
- ["loang"] = 10220,
- ["roang"] = 10221,
- ["LongLeftArrow"] = 10229,
- ["longleftarrow"] = 10229,
- ["xlarr"] = 10229,
- ["LongRightArrow"] = 10230,
- ["longrightarrow"] = 10230,
- ["xrarr"] = 10230,
- ["LongLeftRightArrow"] = 10231,
- ["longleftrightarrow"] = 10231,
- ["xharr"] = 10231,
- ["DoubleLongLeftArrow"] = 10232,
- ["Longleftarrow"] = 10232,
- ["xlArr"] = 10232,
- ["DoubleLongRightArrow"] = 10233,
- ["Longrightarrow"] = 10233,
- ["xrArr"] = 10233,
- ["DoubleLongLeftRightArrow"] = 10234,
- ["Longleftrightarrow"] = 10234,
- ["xhArr"] = 10234,
- ["longmapsto"] = 10236,
- ["xmap"] = 10236,
- ["dzigrarr"] = 10239,
- ["nvlArr"] = 10498,
- ["nvrArr"] = 10499,
- ["nvHarr"] = 10500,
- ["Map"] = 10501,
- ["lbarr"] = 10508,
- ["bkarow"] = 10509,
- ["rbarr"] = 10509,
- ["lBarr"] = 10510,
- ["dbkarow"] = 10511,
- ["rBarr"] = 10511,
- ["RBarr"] = 10512,
- ["drbkarow"] = 10512,
- ["DDotrahd"] = 10513,
- ["UpArrowBar"] = 10514,
- ["DownArrowBar"] = 10515,
- ["Rarrtl"] = 10518,
- ["latail"] = 10521,
- ["ratail"] = 10522,
- ["lAtail"] = 10523,
- ["rAtail"] = 10524,
- ["larrfs"] = 10525,
- ["rarrfs"] = 10526,
- ["larrbfs"] = 10527,
- ["rarrbfs"] = 10528,
- ["nwarhk"] = 10531,
- ["nearhk"] = 10532,
- ["hksearow"] = 10533,
- ["searhk"] = 10533,
- ["hkswarow"] = 10534,
- ["swarhk"] = 10534,
- ["nwnear"] = 10535,
- ["nesear"] = 10536,
- ["toea"] = 10536,
- ["seswar"] = 10537,
- ["tosa"] = 10537,
- ["swnwar"] = 10538,
- ["nrarrc"] = {10547, 824},
- ["rarrc"] = 10547,
- ["cudarrr"] = 10549,
- ["ldca"] = 10550,
- ["rdca"] = 10551,
- ["cudarrl"] = 10552,
- ["larrpl"] = 10553,
- ["curarrm"] = 10556,
- ["cularrp"] = 10557,
- ["rarrpl"] = 10565,
- ["harrcir"] = 10568,
- ["Uarrocir"] = 10569,
- ["lurdshar"] = 10570,
- ["ldrushar"] = 10571,
- ["LeftRightVector"] = 10574,
- ["RightUpDownVector"] = 10575,
- ["DownLeftRightVector"] = 10576,
- ["LeftUpDownVector"] = 10577,
- ["LeftVectorBar"] = 10578,
- ["RightVectorBar"] = 10579,
- ["RightUpVectorBar"] = 10580,
- ["RightDownVectorBar"] = 10581,
- ["DownLeftVectorBar"] = 10582,
- ["DownRightVectorBar"] = 10583,
- ["LeftUpVectorBar"] = 10584,
- ["LeftDownVectorBar"] = 10585,
- ["LeftTeeVector"] = 10586,
- ["RightTeeVector"] = 10587,
- ["RightUpTeeVector"] = 10588,
- ["RightDownTeeVector"] = 10589,
- ["DownLeftTeeVector"] = 10590,
- ["DownRightTeeVector"] = 10591,
- ["LeftUpTeeVector"] = 10592,
- ["LeftDownTeeVector"] = 10593,
- ["lHar"] = 10594,
- ["uHar"] = 10595,
- ["rHar"] = 10596,
- ["dHar"] = 10597,
- ["luruhar"] = 10598,
- ["ldrdhar"] = 10599,
- ["ruluhar"] = 10600,
- ["rdldhar"] = 10601,
- ["lharul"] = 10602,
- ["llhard"] = 10603,
- ["rharul"] = 10604,
- ["lrhard"] = 10605,
- ["UpEquilibrium"] = 10606,
- ["udhar"] = 10606,
- ["ReverseUpEquilibrium"] = 10607,
- ["duhar"] = 10607,
- ["RoundImplies"] = 10608,
- ["erarr"] = 10609,
- ["simrarr"] = 10610,
- ["larrsim"] = 10611,
- ["rarrsim"] = 10612,
- ["rarrap"] = 10613,
- ["ltlarr"] = 10614,
- ["gtrarr"] = 10616,
- ["subrarr"] = 10617,
- ["suplarr"] = 10619,
- ["lfisht"] = 10620,
- ["rfisht"] = 10621,
- ["ufisht"] = 10622,
- ["dfisht"] = 10623,
- ["lopar"] = 10629,
- ["ropar"] = 10630,
- ["lbrke"] = 10635,
- ["rbrke"] = 10636,
- ["lbrkslu"] = 10637,
- ["rbrksld"] = 10638,
- ["lbrksld"] = 10639,
- ["rbrkslu"] = 10640,
- ["langd"] = 10641,
- ["rangd"] = 10642,
- ["lparlt"] = 10643,
- ["rpargt"] = 10644,
- ["gtlPar"] = 10645,
- ["ltrPar"] = 10646,
- ["vzigzag"] = 10650,
- ["vangrt"] = 10652,
- ["angrtvbd"] = 10653,
- ["ange"] = 10660,
- ["range"] = 10661,
- ["dwangle"] = 10662,
- ["uwangle"] = 10663,
- ["angmsdaa"] = 10664,
- ["angmsdab"] = 10665,
- ["angmsdac"] = 10666,
- ["angmsdad"] = 10667,
- ["angmsdae"] = 10668,
- ["angmsdaf"] = 10669,
- ["angmsdag"] = 10670,
- ["angmsdah"] = 10671,
- ["bemptyv"] = 10672,
- ["demptyv"] = 10673,
- ["cemptyv"] = 10674,
- ["raemptyv"] = 10675,
- ["laemptyv"] = 10676,
- ["ohbar"] = 10677,
- ["omid"] = 10678,
- ["opar"] = 10679,
- ["operp"] = 10681,
- ["olcross"] = 10683,
- ["odsold"] = 10684,
- ["olcir"] = 10686,
- ["ofcir"] = 10687,
- ["olt"] = 10688,
- ["ogt"] = 10689,
- ["cirscir"] = 10690,
- ["cirE"] = 10691,
- ["solb"] = 10692,
- ["bsolb"] = 10693,
- ["boxbox"] = 10697,
- ["trisb"] = 10701,
- ["rtriltri"] = 10702,
- ["LeftTriangleBar"] = 10703,
- ["NotLeftTriangleBar"] = {10703, 824},
- ["NotRightTriangleBar"] = {10704, 824},
- ["RightTriangleBar"] = 10704,
- ["iinfin"] = 10716,
- ["infintie"] = 10717,
- ["nvinfin"] = 10718,
- ["eparsl"] = 10723,
- ["smeparsl"] = 10724,
- ["eqvparsl"] = 10725,
- ["blacklozenge"] = 10731,
- ["lozf"] = 10731,
- ["RuleDelayed"] = 10740,
- ["dsol"] = 10742,
- ["bigodot"] = 10752,
- ["xodot"] = 10752,
- ["bigoplus"] = 10753,
- ["xoplus"] = 10753,
- ["bigotimes"] = 10754,
- ["xotime"] = 10754,
- ["biguplus"] = 10756,
- ["xuplus"] = 10756,
- ["bigsqcup"] = 10758,
- ["xsqcup"] = 10758,
- ["iiiint"] = 10764,
- ["qint"] = 10764,
- ["fpartint"] = 10765,
- ["cirfnint"] = 10768,
- ["awint"] = 10769,
- ["rppolint"] = 10770,
- ["scpolint"] = 10771,
- ["npolint"] = 10772,
- ["pointint"] = 10773,
- ["quatint"] = 10774,
- ["intlarhk"] = 10775,
- ["pluscir"] = 10786,
- ["plusacir"] = 10787,
- ["simplus"] = 10788,
- ["plusdu"] = 10789,
- ["plussim"] = 10790,
- ["plustwo"] = 10791,
- ["mcomma"] = 10793,
- ["minusdu"] = 10794,
- ["loplus"] = 10797,
- ["roplus"] = 10798,
- ["Cross"] = 10799,
- ["timesd"] = 10800,
- ["timesbar"] = 10801,
- ["smashp"] = 10803,
- ["lotimes"] = 10804,
- ["rotimes"] = 10805,
- ["otimesas"] = 10806,
- ["Otimes"] = 10807,
- ["odiv"] = 10808,
- ["triplus"] = 10809,
- ["triminus"] = 10810,
- ["tritime"] = 10811,
- ["intprod"] = 10812,
- ["iprod"] = 10812,
- ["amalg"] = 10815,
- ["capdot"] = 10816,
- ["ncup"] = 10818,
- ["ncap"] = 10819,
- ["capand"] = 10820,
- ["cupor"] = 10821,
- ["cupcap"] = 10822,
- ["capcup"] = 10823,
- ["cupbrcap"] = 10824,
- ["capbrcup"] = 10825,
- ["cupcup"] = 10826,
- ["capcap"] = 10827,
- ["ccups"] = 10828,
- ["ccaps"] = 10829,
- ["ccupssm"] = 10832,
- ["And"] = 10835,
- ["Or"] = 10836,
- ["andand"] = 10837,
- ["oror"] = 10838,
- ["orslope"] = 10839,
- ["andslope"] = 10840,
- ["andv"] = 10842,
- ["orv"] = 10843,
- ["andd"] = 10844,
- ["ord"] = 10845,
- ["wedbar"] = 10847,
- ["sdote"] = 10854,
- ["simdot"] = 10858,
- ["congdot"] = 10861,
- ["ncongdot"] = {10861, 824},
- ["easter"] = 10862,
- ["apacir"] = 10863,
- ["apE"] = 10864,
- ["napE"] = {10864, 824},
- ["eplus"] = 10865,
- ["pluse"] = 10866,
- ["Esim"] = 10867,
- ["Colone"] = 10868,
- ["Equal"] = 10869,
- ["ddotseq"] = 10871,
- ["eDDot"] = 10871,
- ["equivDD"] = 10872,
- ["ltcir"] = 10873,
- ["gtcir"] = 10874,
- ["ltquest"] = 10875,
- ["gtquest"] = 10876,
- ["LessSlantEqual"] = 10877,
- ["NotLessSlantEqual"] = {10877, 824},
- ["leqslant"] = 10877,
- ["les"] = 10877,
- ["nleqslant"] = {10877, 824},
- ["nles"] = {10877, 824},
- ["GreaterSlantEqual"] = 10878,
- ["NotGreaterSlantEqual"] = {10878, 824},
- ["geqslant"] = 10878,
- ["ges"] = 10878,
- ["ngeqslant"] = {10878, 824},
- ["nges"] = {10878, 824},
- ["lesdot"] = 10879,
- ["gesdot"] = 10880,
- ["lesdoto"] = 10881,
- ["gesdoto"] = 10882,
- ["lesdotor"] = 10883,
- ["gesdotol"] = 10884,
- ["lap"] = 10885,
- ["lessapprox"] = 10885,
- ["gap"] = 10886,
- ["gtrapprox"] = 10886,
- ["lne"] = 10887,
- ["lneq"] = 10887,
- ["gne"] = 10888,
- ["gneq"] = 10888,
- ["lnap"] = 10889,
- ["lnapprox"] = 10889,
- ["gnap"] = 10890,
- ["gnapprox"] = 10890,
- ["lEg"] = 10891,
- ["lesseqqgtr"] = 10891,
- ["gEl"] = 10892,
- ["gtreqqless"] = 10892,
- ["lsime"] = 10893,
- ["gsime"] = 10894,
- ["lsimg"] = 10895,
- ["gsiml"] = 10896,
- ["lgE"] = 10897,
- ["glE"] = 10898,
- ["lesges"] = 10899,
- ["gesles"] = 10900,
- ["els"] = 10901,
- ["eqslantless"] = 10901,
- ["egs"] = 10902,
- ["eqslantgtr"] = 10902,
- ["elsdot"] = 10903,
- ["egsdot"] = 10904,
- ["el"] = 10905,
- ["eg"] = 10906,
- ["siml"] = 10909,
- ["simg"] = 10910,
- ["simlE"] = 10911,
- ["simgE"] = 10912,
- ["LessLess"] = 10913,
- ["NotNestedLessLess"] = {10913, 824},
- ["GreaterGreater"] = 10914,
- ["NotNestedGreaterGreater"] = {10914, 824},
- ["glj"] = 10916,
- ["gla"] = 10917,
- ["ltcc"] = 10918,
- ["gtcc"] = 10919,
- ["lescc"] = 10920,
- ["gescc"] = 10921,
- ["smt"] = 10922,
- ["lat"] = 10923,
- ["smte"] = 10924,
- ["smtes"] = {10924, 65024},
- ["late"] = 10925,
- ["lates"] = {10925, 65024},
- ["bumpE"] = 10926,
- ["NotPrecedesEqual"] = {10927, 824},
- ["PrecedesEqual"] = 10927,
- ["npre"] = {10927, 824},
- ["npreceq"] = {10927, 824},
- ["pre"] = 10927,
- ["preceq"] = 10927,
- ["NotSucceedsEqual"] = {10928, 824},
- ["SucceedsEqual"] = 10928,
- ["nsce"] = {10928, 824},
- ["nsucceq"] = {10928, 824},
- ["sce"] = 10928,
- ["succeq"] = 10928,
- ["prE"] = 10931,
- ["scE"] = 10932,
- ["precneqq"] = 10933,
- ["prnE"] = 10933,
- ["scnE"] = 10934,
- ["succneqq"] = 10934,
- ["prap"] = 10935,
- ["precapprox"] = 10935,
- ["scap"] = 10936,
- ["succapprox"] = 10936,
- ["precnapprox"] = 10937,
- ["prnap"] = 10937,
- ["scnap"] = 10938,
- ["succnapprox"] = 10938,
- ["Pr"] = 10939,
- ["Sc"] = 10940,
- ["subdot"] = 10941,
- ["supdot"] = 10942,
- ["subplus"] = 10943,
- ["supplus"] = 10944,
- ["submult"] = 10945,
- ["supmult"] = 10946,
- ["subedot"] = 10947,
- ["supedot"] = 10948,
- ["nsubE"] = {10949, 824},
- ["nsubseteqq"] = {10949, 824},
- ["subE"] = 10949,
- ["subseteqq"] = 10949,
- ["nsupE"] = {10950, 824},
- ["nsupseteqq"] = {10950, 824},
- ["supE"] = 10950,
- ["supseteqq"] = 10950,
- ["subsim"] = 10951,
- ["supsim"] = 10952,
- ["subnE"] = 10955,
- ["subsetneqq"] = 10955,
- ["varsubsetneqq"] = {10955, 65024},
- ["vsubnE"] = {10955, 65024},
- ["supnE"] = 10956,
- ["supsetneqq"] = 10956,
- ["varsupsetneqq"] = {10956, 65024},
- ["vsupnE"] = {10956, 65024},
- ["csub"] = 10959,
- ["csup"] = 10960,
- ["csube"] = 10961,
- ["csupe"] = 10962,
- ["subsup"] = 10963,
- ["supsub"] = 10964,
- ["subsub"] = 10965,
- ["supsup"] = 10966,
- ["suphsub"] = 10967,
- ["supdsub"] = 10968,
- ["forkv"] = 10969,
- ["topfork"] = 10970,
- ["mlcp"] = 10971,
- ["Dashv"] = 10980,
- ["DoubleLeftTee"] = 10980,
- ["Vdashl"] = 10982,
- ["Barv"] = 10983,
- ["vBar"] = 10984,
- ["vBarv"] = 10985,
- ["Vbar"] = 10987,
- ["Not"] = 10988,
- ["bNot"] = 10989,
- ["rnmid"] = 10990,
- ["cirmid"] = 10991,
- ["midcir"] = 10992,
- ["topcir"] = 10993,
- ["nhpar"] = 10994,
- ["parsim"] = 10995,
- ["nparsl"] = {11005, 8421},
- ["parsl"] = 11005,
- ["fflig"] = 64256,
- ["filig"] = 64257,
- ["fllig"] = 64258,
- ["ffilig"] = 64259,
- ["ffllig"] = 64260,
- ["Ascr"] = 119964,
- ["Cscr"] = 119966,
- ["Dscr"] = 119967,
- ["Gscr"] = 119970,
- ["Jscr"] = 119973,
- ["Kscr"] = 119974,
- ["Nscr"] = 119977,
- ["Oscr"] = 119978,
- ["Pscr"] = 119979,
- ["Qscr"] = 119980,
- ["Sscr"] = 119982,
- ["Tscr"] = 119983,
- ["Uscr"] = 119984,
- ["Vscr"] = 119985,
- ["Wscr"] = 119986,
- ["Xscr"] = 119987,
- ["Yscr"] = 119988,
- ["Zscr"] = 119989,
- ["ascr"] = 119990,
- ["bscr"] = 119991,
- ["cscr"] = 119992,
- ["dscr"] = 119993,
- ["fscr"] = 119995,
- ["hscr"] = 119997,
- ["iscr"] = 119998,
- ["jscr"] = 119999,
- ["kscr"] = 120000,
- ["lscr"] = 120001,
- ["mscr"] = 120002,
- ["nscr"] = 120003,
- ["pscr"] = 120005,
- ["qscr"] = 120006,
- ["rscr"] = 120007,
- ["sscr"] = 120008,
- ["tscr"] = 120009,
- ["uscr"] = 120010,
- ["vscr"] = 120011,
- ["wscr"] = 120012,
- ["xscr"] = 120013,
- ["yscr"] = 120014,
- ["zscr"] = 120015,
- ["Afr"] = 120068,
- ["Bfr"] = 120069,
- ["Dfr"] = 120071,
- ["Efr"] = 120072,
- ["Ffr"] = 120073,
- ["Gfr"] = 120074,
- ["Jfr"] = 120077,
- ["Kfr"] = 120078,
- ["Lfr"] = 120079,
- ["Mfr"] = 120080,
- ["Nfr"] = 120081,
- ["Ofr"] = 120082,
- ["Pfr"] = 120083,
- ["Qfr"] = 120084,
- ["Sfr"] = 120086,
- ["Tfr"] = 120087,
- ["Ufr"] = 120088,
- ["Vfr"] = 120089,
- ["Wfr"] = 120090,
- ["Xfr"] = 120091,
- ["Yfr"] = 120092,
- ["afr"] = 120094,
- ["bfr"] = 120095,
- ["cfr"] = 120096,
- ["dfr"] = 120097,
- ["efr"] = 120098,
- ["ffr"] = 120099,
- ["gfr"] = 120100,
- ["hfr"] = 120101,
- ["ifr"] = 120102,
- ["jfr"] = 120103,
- ["kfr"] = 120104,
- ["lfr"] = 120105,
- ["mfr"] = 120106,
- ["nfr"] = 120107,
- ["ofr"] = 120108,
- ["pfr"] = 120109,
- ["qfr"] = 120110,
- ["rfr"] = 120111,
- ["sfr"] = 120112,
- ["tfr"] = 120113,
- ["ufr"] = 120114,
- ["vfr"] = 120115,
- ["wfr"] = 120116,
- ["xfr"] = 120117,
- ["yfr"] = 120118,
- ["zfr"] = 120119,
- ["Aopf"] = 120120,
- ["Bopf"] = 120121,
- ["Dopf"] = 120123,
- ["Eopf"] = 120124,
- ["Fopf"] = 120125,
- ["Gopf"] = 120126,
- ["Iopf"] = 120128,
- ["Jopf"] = 120129,
- ["Kopf"] = 120130,
- ["Lopf"] = 120131,
- ["Mopf"] = 120132,
- ["Oopf"] = 120134,
- ["Sopf"] = 120138,
- ["Topf"] = 120139,
- ["Uopf"] = 120140,
- ["Vopf"] = 120141,
- ["Wopf"] = 120142,
- ["Xopf"] = 120143,
- ["Yopf"] = 120144,
- ["aopf"] = 120146,
- ["bopf"] = 120147,
- ["copf"] = 120148,
- ["dopf"] = 120149,
- ["eopf"] = 120150,
- ["fopf"] = 120151,
- ["gopf"] = 120152,
- ["hopf"] = 120153,
- ["iopf"] = 120154,
- ["jopf"] = 120155,
- ["kopf"] = 120156,
- ["lopf"] = 120157,
- ["mopf"] = 120158,
- ["nopf"] = 120159,
- ["oopf"] = 120160,
- ["popf"] = 120161,
- ["qopf"] = 120162,
- ["ropf"] = 120163,
- ["sopf"] = 120164,
- ["topf"] = 120165,
- ["uopf"] = 120166,
- ["vopf"] = 120167,
- ["wopf"] = 120168,
- ["xopf"] = 120169,
- ["yopf"] = 120170,
- ["zopf"] = 120171,
-}
-function entities.dec_entity(s)
- local n = tonumber(s)
- if n == nil then
- return "&#" .. s .. ";" -- fallback for unknown entities
- end
- return unicode.utf8.char(n)
-end
-function entities.hex_entity(s)
- local n = tonumber("0x"..s)
- if n == nil then
- return "&#x" .. s .. ";" -- fallback for unknown entities
- end
- return unicode.utf8.char(n)
-end
-function entities.hex_entity_with_x_char(x, s)
- local n = tonumber("0x"..s)
- if n == nil then
- return "&#" .. x .. s .. ";" -- fallback for unknown entities
- end
- return unicode.utf8.char(n)
-end
-function entities.char_entity(s)
- local code_points = character_entities[s]
- if code_points == nil then
- return "&" .. s .. ";"
- end
- if type(code_points) ~= 'table' then
- code_points = {code_points}
- end
- local char_table = {}
- for _, code_point in ipairs(code_points) do
- table.insert(char_table, unicode.utf8.char(code_point))
- end
- return table.concat(char_table)
-end
-M.writer = {}
-function M.writer.new(options)
- local self = {}
- self.options = options
- self.flatten_inlines = false
- local slice_specifiers = {}
- for specifier in options.slice:gmatch("[^%s]+") do
- table.insert(slice_specifiers, specifier)
- end
-
- if #slice_specifiers == 2 then
- self.slice_begin, self.slice_end = table.unpack(slice_specifiers)
- local slice_begin_type = self.slice_begin:sub(1, 1)
- if slice_begin_type ~= "^" and slice_begin_type ~= "$" then
- self.slice_begin = "^" .. self.slice_begin
- end
- local slice_end_type = self.slice_end:sub(1, 1)
- if slice_end_type ~= "^" and slice_end_type ~= "$" then
- self.slice_end = "$" .. self.slice_end
- end
- elseif #slice_specifiers == 1 then
- self.slice_begin = "^" .. slice_specifiers[1]
- self.slice_end = "$" .. slice_specifiers[1]
- end
-
- self.slice_begin_type = self.slice_begin:sub(1, 1)
- self.slice_begin_identifier = self.slice_begin:sub(2) or ""
- self.slice_end_type = self.slice_end:sub(1, 1)
- self.slice_end_identifier = self.slice_end:sub(2) or ""
-
- if self.slice_begin == "^" and self.slice_end ~= "^" then
- self.is_writing = true
- else
- self.is_writing = false
- end
- self.suffix = ".tex"
- self.space = " "
- self.nbsp = "\\markdownRendererNbsp{}"
- function self.plain(s)
- return s
- end
- function self.paragraph(s)
- if not self.is_writing then return "" end
- return s
- end
- function self.pack(name)
- return [[\input{]] .. name .. [[}\relax]]
- end
- self.interblocksep_text = "\\markdownRendererInterblockSeparator\n{}"
- function self.interblocksep()
- if not self.is_writing then return "" end
- return self.interblocksep_text
- end
- self.paragraphsep_text = "\\markdownRendererParagraphSeparator\n{}"
- function self.paragraphsep()
- if not self.is_writing then return "" end
- return self.paragraphsep_text
- end
- self.undosep_text = "\\markdownRendererUndoSeparator\n{}"
- function self.undosep()
- if not self.is_writing then return "" end
- return self.undosep_text
- end
- self.soft_line_break = function()
- if self.flatten_inlines then return "\n" end
- return "\\markdownRendererSoftLineBreak\n{}"
- end
- self.hard_line_break = function()
- if self.flatten_inlines then return "\n" end
- return "\\markdownRendererHardLineBreak\n{}"
- end
- self.ellipsis = "\\markdownRendererEllipsis{}"
- function self.thematic_break()
- if not self.is_writing then return "" end
- return "\\markdownRendererThematicBreak{}"
- end
- self.escaped_uri_chars = {
- ["{"] = "\\markdownRendererLeftBrace{}",
- ["}"] = "\\markdownRendererRightBrace{}",
- ["\\"] = "\\markdownRendererBackslash{}",
- }
- self.escaped_minimal_strings = {
- ["^^"] = "\\markdownRendererCircumflex\\markdownRendererCircumflex ",
- ["☒"] = "\\markdownRendererTickedBox{}",
- ["⌛"] = "\\markdownRendererHalfTickedBox{}",
- ["☐"] = "\\markdownRendererUntickedBox{}",
- [entities.hex_entity('FFFD')] = "\\markdownRendererReplacementCharacter{}",
- }
- self.escaped_strings = util.table_copy(self.escaped_minimal_strings)
- self.escaped_strings[entities.hex_entity('00A0')] = self.nbsp
- self.escaped_chars = {
- ["{"] = "\\markdownRendererLeftBrace{}",
- ["}"] = "\\markdownRendererRightBrace{}",
- ["%"] = "\\markdownRendererPercentSign{}",
- ["\\"] = "\\markdownRendererBackslash{}",
- ["#"] = "\\markdownRendererHash{}",
- ["$"] = "\\markdownRendererDollarSign{}",
- ["&"] = "\\markdownRendererAmpersand{}",
- ["_"] = "\\markdownRendererUnderscore{}",
- ["^"] = "\\markdownRendererCircumflex{}",
- ["~"] = "\\markdownRendererTilde{}",
- ["|"] = "\\markdownRendererPipe{}",
- [entities.hex_entity('0000')] = "\\markdownRendererReplacementCharacter{}",
- }
- local function create_escaper(char_escapes, string_escapes)
- local escape = util.escaper(char_escapes, string_escapes)
- return function(s)
- if self.flatten_inlines then return s end
- return escape(s)
- end
- end
- local escape_typographic_text = create_escaper(
- self.escaped_chars, self.escaped_strings)
- local escape_programmatic_text = create_escaper(
- self.escaped_uri_chars, self.escaped_minimal_strings)
- local escape_minimal = create_escaper(
- {}, self.escaped_minimal_strings)
- self.escape = escape_typographic_text
- self.math = escape_minimal
- if options.hybrid then
- self.identifier = escape_minimal
- self.string = escape_minimal
- self.uri = escape_minimal
- self.infostring = escape_minimal
- else
- self.identifier = escape_programmatic_text
- self.string = escape_typographic_text
- self.uri = escape_programmatic_text
- self.infostring = escape_programmatic_text
- end
- function self.code(s, attributes)
- if self.flatten_inlines then return s end
- local buf = {}
- if attributes ~= nil then
- table.insert(buf,
- "\\markdownRendererCodeSpanAttributeContextBegin\n")
- table.insert(buf, self.attributes(attributes))
- end
- table.insert(buf,
- {"\\markdownRendererCodeSpan{", self.escape(s), "}"})
- if attributes ~= nil then
- table.insert(buf,
- "\\markdownRendererCodeSpanAttributeContextEnd{}")
- end
- return buf
- end
- function self.link(lab, src, tit, attributes)
- if self.flatten_inlines then return lab end
- local buf = {}
- if attributes ~= nil then
- table.insert(buf,
- "\\markdownRendererLinkAttributeContextBegin\n")
- table.insert(buf, self.attributes(attributes))
- end
- table.insert(buf, {"\\markdownRendererLink{",lab,"}",
- "{",self.escape(src),"}",
- "{",self.uri(src),"}",
- "{",self.string(tit or ""),"}"})
- if attributes ~= nil then
- table.insert(buf,
- "\\markdownRendererLinkAttributeContextEnd{}")
- end
- return buf
- end
- function self.image(lab, src, tit, attributes)
- if self.flatten_inlines then return lab end
- local buf = {}
- if attributes ~= nil then
- table.insert(buf,
- "\\markdownRendererImageAttributeContextBegin\n")
- table.insert(buf, self.attributes(attributes))
- end
- table.insert(buf, {"\\markdownRendererImage{",lab,"}",
- "{",self.string(src),"}",
- "{",self.uri(src),"}",
- "{",self.string(tit or ""),"}"})
- if attributes ~= nil then
- table.insert(buf,
- "\\markdownRendererImageAttributeContextEnd{}")
- end
- return buf
- end
- function self.bulletlist(items,tight)
- if not self.is_writing then return "" end
- local buffer = {}
- for _,item in ipairs(items) do
- if item ~= "" then
- buffer[#buffer + 1] = self.bulletitem(item)
- end
- end
- local contents = util.intersperse(buffer,"\n")
- if tight and options.tightLists then
- return {"\\markdownRendererUlBeginTight\n",contents,
- "\n\\markdownRendererUlEndTight "}
- else
- return {"\\markdownRendererUlBegin\n",contents,
- "\n\\markdownRendererUlEnd "}
- end
- end
- function self.bulletitem(s)
- return {"\\markdownRendererUlItem ",s,
- "\\markdownRendererUlItemEnd "}
- end
- function self.orderedlist(items,tight,startnum)
- if not self.is_writing then return "" end
- local buffer = {}
- local num = startnum
- for _,item in ipairs(items) do
- if item ~= "" then
- buffer[#buffer + 1] = self.ordereditem(item,num)
- end
- if num ~= nil and item ~= "" then
- num = num + 1
- end
- end
- local contents = util.intersperse(buffer,"\n")
- if tight and options.tightLists then
- return {"\\markdownRendererOlBeginTight\n",contents,
- "\n\\markdownRendererOlEndTight "}
- else
- return {"\\markdownRendererOlBegin\n",contents,
- "\n\\markdownRendererOlEnd "}
- end
- end
- function self.ordereditem(s,num)
- if num ~= nil then
- return {"\\markdownRendererOlItemWithNumber{",num,"}",s,
- "\\markdownRendererOlItemEnd "}
- else
- return {"\\markdownRendererOlItem ",s,
- "\\markdownRendererOlItemEnd "}
- end
- end
- function self.inline_html_comment(contents)
- if self.flatten_inlines then return contents end
- return {"\\markdownRendererInlineHtmlComment{",contents,"}"}
- end
- function self.inline_html_tag(contents)
- if self.flatten_inlines then return contents end
- return {"\\markdownRendererInlineHtmlTag{",self.string(contents),"}"}
- end
- function self.block_html_element(s)
- if not self.is_writing then return "" end
- local name = util.cache(options.cacheDir, s, nil, nil, ".verbatim")
- return {"\\markdownRendererInputBlockHtmlElement{",name,"}"}
- end
- function self.emphasis(s)
- if self.flatten_inlines then return s end
- return {"\\markdownRendererEmphasis{",s,"}"}
- end
- function self.tickbox(f)
- if f == 1.0 then
- return "☒ "
- elseif f == 0.0 then
- return "☐ "
- else
- return "⌛ "
- end
- end
- function self.strong(s)
- if self.flatten_inlines then return s end
- return {"\\markdownRendererStrongEmphasis{",s,"}"}
- end
- function self.blockquote(s)
- if not self.is_writing then return "" end
- return {"\\markdownRendererBlockQuoteBegin\n",s,
- "\\markdownRendererBlockQuoteEnd "}
- end
- function self.verbatim(s)
- if not self.is_writing then return "" end
- s = s:gsub("\n$", "")
- local name = util.cache_verbatim(options.cacheDir, s)
- return {"\\markdownRendererInputVerbatim{",name,"}"}
- end
- function self.document(d)
- local buf = {"\\markdownRendererDocumentBegin\n", d}
-
- -- pop all attributes
- table.insert(buf, self.pop_attributes())
-
- table.insert(buf, "\\markdownRendererDocumentEnd")
-
- return buf
- end
- local seen_identifiers = {}
- local key_value_regex = "([^= ]+)%s*=%s*(.*)"
- local function normalize_attributes(attributes, auto_identifiers)
- -- normalize attributes
- local normalized_attributes = {}
- local has_explicit_identifiers = false
- local key, value
- for _, attribute in ipairs(attributes or {}) do
- if attribute:sub(1, 1) == "#" then
- table.insert(normalized_attributes, attribute)
- has_explicit_identifiers = true
- seen_identifiers[attribute:sub(2)] = true
- elseif attribute:sub(1, 1) == "." then
- table.insert(normalized_attributes, attribute)
- else
- key, value = attribute:match(key_value_regex)
- if key:lower() == "id" then
- table.insert(normalized_attributes, "#" .. value)
- elseif key:lower() == "class" then
- local classes = {}
- for class in value:gmatch("%S+") do
- table.insert(classes, class)
- end
- table.sort(classes)
- for _, class in ipairs(classes) do
- table.insert(normalized_attributes, "." .. class)
- end
- else
- table.insert(normalized_attributes, attribute)
- end
- end
- end
-
- -- if no explicit identifiers exist, add auto identifiers
- if not has_explicit_identifiers and auto_identifiers ~= nil then
- local seen_auto_identifiers = {}
- for _, auto_identifier in ipairs(auto_identifiers) do
- if seen_auto_identifiers[auto_identifier] == nil then
- seen_auto_identifiers[auto_identifier] = true
- if seen_identifiers[auto_identifier] == nil then
- seen_identifiers[auto_identifier] = true
- table.insert(normalized_attributes,
- "#" .. auto_identifier)
- else
- local auto_identifier_number = 1
- while true do
- local numbered_auto_identifier = auto_identifier .. "-"
- .. auto_identifier_number
- if seen_identifiers[numbered_auto_identifier] == nil then
- seen_identifiers[numbered_auto_identifier] = true
- table.insert(normalized_attributes,
- "#" .. numbered_auto_identifier)
- break
- end
- auto_identifier_number = auto_identifier_number + 1
- end
- end
- end
- end
- end
-
- -- sort and deduplicate normalized attributes
- table.sort(normalized_attributes)
- local seen_normalized_attributes = {}
- local deduplicated_normalized_attributes = {}
- for _, attribute in ipairs(normalized_attributes) do
- if seen_normalized_attributes[attribute] == nil then
- seen_normalized_attributes[attribute] = true
- table.insert(deduplicated_normalized_attributes, attribute)
- end
- end
-
- return deduplicated_normalized_attributes
- end
-
- function self.attributes(attributes, should_normalize_attributes)
- local normalized_attributes
- if should_normalize_attributes == false then
- normalized_attributes = attributes
- else
- normalized_attributes = normalize_attributes(attributes)
- end
-
- local buf = {}
- local key, value
- for _, attribute in ipairs(normalized_attributes) do
- if attribute:sub(1, 1) == "#" then
- table.insert(buf, {"\\markdownRendererAttributeIdentifier{",
- attribute:sub(2), "}"})
- elseif attribute:sub(1, 1) == "." then
- table.insert(buf, {"\\markdownRendererAttributeClassName{",
- attribute:sub(2), "}"})
- else
- key, value = attribute:match(key_value_regex)
- table.insert(buf, {"\\markdownRendererAttributeKeyValue{",
- key, "}{", value, "}"})
- end
- end
-
- return buf
- end
- self.active_attributes = {}
- self.attribute_type_levels = {}
- setmetatable(self.attribute_type_levels,
- { __index = function() return 0 end })
- local function apply_attributes()
- local buf = {}
- for i = 1, #self.active_attributes do
- local start_output = self.active_attributes[i][3]
- if start_output ~= nil then
- table.insert(buf, start_output)
- end
- end
- return buf
- end
-
- local function tear_down_attributes()
- local buf = {}
- for i = #self.active_attributes, 1, -1 do
- local end_output = self.active_attributes[i][4]
- if end_output ~= nil then
- table.insert(buf, end_output)
- end
- end
- return buf
- end
- function self.push_attributes(attribute_type, attributes,
- start_output, end_output)
- local attribute_type_level = self.attribute_type_levels[attribute_type]
- self.attribute_type_levels[attribute_type] = attribute_type_level + 1
-
- -- index attributes in a hash table for easy lookup
- attributes = attributes or {}
- for i = 1, #attributes do
- attributes[attributes[i]] = true
- end
-
- local buf = {}
- -- handle slicing
- if attributes["#" .. self.slice_end_identifier] ~= nil and
- self.slice_end_type == "^" then
- if self.is_writing then
- table.insert(buf, self.undosep())
- table.insert(buf, tear_down_attributes())
- end
- self.is_writing = false
- end
- if attributes["#" .. self.slice_begin_identifier] ~= nil and
- self.slice_begin_type == "^" then
- table.insert(buf, apply_attributes())
- self.is_writing = true
- end
- if self.is_writing and start_output ~= nil then
- table.insert(buf, start_output)
- end
- table.insert(self.active_attributes,
- {attribute_type, attributes,
- start_output, end_output})
- return buf
- end
-
- function self.pop_attributes(attribute_type)
- local buf = {}
- -- pop attributes until we find attributes of correct type
- -- or until no attributes remain
- local current_attribute_type = false
- while current_attribute_type ~= attribute_type and
- #self.active_attributes > 0 do
- local attributes, _, end_output
- current_attribute_type, attributes, _, end_output = table.unpack(
- self.active_attributes[#self.active_attributes])
- local attribute_type_level = self.attribute_type_levels[current_attribute_type]
- self.attribute_type_levels[current_attribute_type] = attribute_type_level - 1
- if self.is_writing and end_output ~= nil then
- table.insert(buf, end_output)
- end
- table.remove(self.active_attributes, #self.active_attributes)
- -- handle slicing
- if attributes["#" .. self.slice_end_identifier] ~= nil
- and self.slice_end_type == "$" then
- if self.is_writing then
- table.insert(buf, self.undosep())
- table.insert(buf, tear_down_attributes())
- end
- self.is_writing = false
- end
- if attributes["#" .. self.slice_begin_identifier] ~= nil and
- self.slice_begin_type == "$" then
- self.is_writing = true
- table.insert(buf, apply_attributes())
- end
- end
- return buf
- end
- local function create_auto_identifier(s)
- local buffer = {}
- local prev_space = false
- local letter_found = false
-
- for _, code in utf8.codes(uni_algos.normalize.NFC(s)) do
- local char = utf8.char(code)
-
- -- Remove everything up to the first letter.
- if not letter_found then
- local is_letter = unicode.utf8.match(char, "%a")
- if is_letter then
- letter_found = true
- else
- goto continue
- end
- end
-
- -- Remove all non-alphanumeric characters, except underscores, hyphens, and periods.
- if not unicode.utf8.match(char, "[%w_%-%.%s]") then
- goto continue
- end
-
- -- Replace all spaces and newlines with hyphens.
- if unicode.utf8.match(char, "[%s\n]") then
- char = "-"
- if prev_space then
- goto continue
- else
- prev_space = true
- end
- else
- -- Convert all alphabetic characters to lowercase.
- char = unicode.utf8.lower(char)
- prev_space = false
- end
-
- table.insert(buffer, char)
-
- ::continue::
- end
-
- if prev_space then
- table.remove(buffer)
- end
-
- local identifier = #buffer == 0 and "section" or table.concat(buffer, "")
- return identifier
- end
- local function create_gfm_auto_identifier(s)
- local buffer = {}
- local prev_space = false
- local letter_found = false
-
- for _, code in utf8.codes(uni_algos.normalize.NFC(s)) do
- local char = utf8.char(code)
-
- -- Remove everything up to the first non-space.
- if not letter_found then
- local is_letter = unicode.utf8.match(char, "%S")
- if is_letter then
- letter_found = true
- else
- goto continue
- end
- end
-
- -- Remove all non-alphanumeric characters, except underscores and hyphens.
- if not unicode.utf8.match(char, "[%w_%-%s]") then
- prev_space = false
- goto continue
- end
-
- -- Replace all spaces and newlines with hyphens.
- if unicode.utf8.match(char, "[%s\n]") then
- char = "-"
- if prev_space then
- goto continue
- else
- prev_space = true
- end
- else
- -- Convert all alphabetic characters to lowercase.
- char = unicode.utf8.lower(char)
- prev_space = false
- end
-
- table.insert(buffer, char)
-
- ::continue::
- end
-
- if prev_space then
- table.remove(buffer)
- end
-
- local identifier = #buffer == 0 and "section" or table.concat(buffer, "")
- return identifier
- end
- self.secbegin_text = "\\markdownRendererSectionBegin\n"
- self.secend_text = "\n\\markdownRendererSectionEnd "
- function self.heading(s, level, attributes)
- local buf = {}
- local flat_text, inlines = table.unpack(s)
-
- -- push empty attributes for implied sections
- while self.attribute_type_levels["heading"] < level - 1 do
- table.insert(buf,
- self.push_attributes("heading",
- nil,
- self.secbegin_text,
- self.secend_text))
- end
-
- -- pop attributes for sections that have ended
- while self.attribute_type_levels["heading"] >= level do
- table.insert(buf, self.pop_attributes("heading"))
- end
-
- -- construct attributes for the new section
- local auto_identifiers = {}
- if self.options.autoIdentifiers then
- table.insert(auto_identifiers, create_auto_identifier(flat_text))
- end
- if self.options.gfmAutoIdentifiers then
- table.insert(auto_identifiers, create_gfm_auto_identifier(flat_text))
- end
- local normalized_attributes = normalize_attributes(attributes, auto_identifiers)
-
- -- push attributes for the new section
- local start_output = {}
- local end_output = {}
- table.insert(start_output, self.secbegin_text)
- table.insert(end_output, self.secend_text)
-
- table.insert(buf, self.push_attributes("heading",
- normalized_attributes,
- start_output,
- end_output))
- assert(self.attribute_type_levels["heading"] == level)
-
- -- render the heading and its attributes
- if self.is_writing and #normalized_attributes > 0 then
- table.insert(buf, "\\markdownRendererHeaderAttributeContextBegin\n")
- table.insert(buf, self.attributes(normalized_attributes, false))
- end
-
- local cmd
- level = level + options.shiftHeadings
- if level <= 1 then
- cmd = "\\markdownRendererHeadingOne"
- elseif level == 2 then
- cmd = "\\markdownRendererHeadingTwo"
- elseif level == 3 then
- cmd = "\\markdownRendererHeadingThree"
- elseif level == 4 then
- cmd = "\\markdownRendererHeadingFour"
- elseif level == 5 then
- cmd = "\\markdownRendererHeadingFive"
- elseif level >= 6 then
- cmd = "\\markdownRendererHeadingSix"
- else
- cmd = ""
- end
- if self.is_writing then
- table.insert(buf, {cmd, "{", inlines, "}"})
- end
-
- if self.is_writing and #normalized_attributes > 0 then
- table.insert(buf, "\\markdownRendererHeaderAttributeContextEnd{}")
- end
-
- return buf
- end
- function self.get_state()
- return {
- is_writing=self.is_writing,
- flatten_inlines=self.flatten_inlines,
- active_attributes={table.unpack(self.active_attributes)},
- }
- end
- function self.set_state(s)
- local previous_state = self.get_state()
- for key, value in pairs(s) do
- self[key] = value
- end
- return previous_state
- end
- function self.defer_call(f)
- local previous_state = self.get_state()
- return function(...)
- local state = self.set_state(previous_state)
- local return_value = f(...)
- self.set_state(state)
- return return_value
- end
- end
-
- return self
-end
-local parsers = {}
-parsers.percent = P("%")
-parsers.at = P("@")
-parsers.comma = P(",")
-parsers.asterisk = P("*")
-parsers.dash = P("-")
-parsers.plus = P("+")
-parsers.underscore = P("_")
-parsers.period = P(".")
-parsers.hash = P("#")
-parsers.dollar = P("$")
-parsers.ampersand = P("&")
-parsers.backtick = P("`")
-parsers.less = P("<")
-parsers.more = P(">")
-parsers.space = P(" ")
-parsers.squote = P("'")
-parsers.dquote = P('"')
-parsers.lparent = P("(")
-parsers.rparent = P(")")
-parsers.lbracket = P("[")
-parsers.rbracket = P("]")
-parsers.lbrace = P("{")
-parsers.rbrace = P("}")
-parsers.circumflex = P("^")
-parsers.slash = P("/")
-parsers.equal = P("=")
-parsers.colon = P(":")
-parsers.semicolon = P(";")
-parsers.exclamation = P("!")
-parsers.pipe = P("|")
-parsers.tilde = P("~")
-parsers.backslash = P("\\")
-parsers.tab = P("\t")
-parsers.newline = P("\n")
-
-parsers.digit = R("09")
-parsers.hexdigit = R("09","af","AF")
-parsers.letter = R("AZ","az")
-parsers.alphanumeric = R("AZ","az","09")
-parsers.keyword = parsers.letter
- * (parsers.alphanumeric + parsers.dash)^0
-
-parsers.doubleasterisks = P("**")
-parsers.doubleunderscores = P("__")
-parsers.doubletildes = P("~~")
-parsers.fourspaces = P(" ")
-
-parsers.any = P(1)
-parsers.succeed = P(true)
-parsers.fail = P(false)
-
-parsers.internal_punctuation = S(":;,.?")
-parsers.ascii_punctuation = S("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~")
-parsers.punctuation = {}
-(function()
- local pathname = kpse.lookup("UnicodeData.txt")
- local file = assert(io.open(pathname, "r"),
- [[Could not open file "UnicodeData.txt"]])
- for line in file:lines() do
- local codepoint, major_category = line:match("^(%x+);[^;]*;(%a)")
- if major_category == "P" or major_category == "S" then
- local code = unicode.utf8.char(tonumber(codepoint, 16))
- if parsers.punctuation[#code] == nil then
- parsers.punctuation[#code] = parsers.fail
- end
- local code_parser = parsers.succeed
- for i = 1, #code do
- local byte = code:sub(i, i)
- local byte_parser = S(byte)
- code_parser = code_parser
- * byte_parser
- end
- parsers.punctuation[#code] = parsers.punctuation[#code]
- + code_parser
- end
- end
- assert(file:close())
-end)()
-
-parsers.escapable = parsers.ascii_punctuation
-parsers.anyescaped = parsers.backslash / "" * parsers.escapable
- + parsers.any
-
-parsers.spacechar = S("\t ")
-parsers.spacing = S(" \n\r\t")
-parsers.nonspacechar = parsers.any - parsers.spacing
-parsers.optionalspace = parsers.spacechar^0
-
-parsers.normalchar = parsers.any - (V("SpecialChar")
- + parsers.spacing)
-parsers.eof = -parsers.any
-parsers.nonindentspace = parsers.space^-3 * - parsers.spacechar
-parsers.indent = parsers.space^-3 * parsers.tab
- + parsers.fourspaces / ""
-parsers.linechar = P(1 - parsers.newline)
-
-parsers.blankline = parsers.optionalspace
- * parsers.newline / "\n"
-parsers.blanklines = parsers.blankline^0
-parsers.skipblanklines = (parsers.optionalspace * parsers.newline)^0
-parsers.indentedline = parsers.indent /""
- * C(parsers.linechar^1 * parsers.newline^-1)
-parsers.optionallyindentedline = parsers.indent^-1 /""
- * C(parsers.linechar^1 * parsers.newline^-1)
-parsers.sp = parsers.spacing^0
-parsers.spnl = parsers.optionalspace
- * (parsers.newline * parsers.optionalspace)^-1
-parsers.line = parsers.linechar^0 * parsers.newline
-parsers.nonemptyline = parsers.line - parsers.blankline
-
-parsers.leader = parsers.space^-3
-
-local function has_trail(indent_table)
- return indent_table ~= nil and
- indent_table.trail ~= nil and
- next(indent_table.trail) ~= nil
-end
-
-local function has_indents(indent_table)
- return indent_table ~= nil and
- indent_table.indents ~= nil and
- next(indent_table.indents) ~= nil
-end
-
-local function add_trail(indent_table, trail_info)
- indent_table.trail = trail_info
- return indent_table
-end
-
-local function remove_trail(indent_table)
- indent_table.trail = nil
- return indent_table
-end
-
-local function update_indent_table(indent_table, new_indent, add)
- indent_table = remove_trail(indent_table)
-
- if not has_indents(indent_table) then
- indent_table.indents = {}
- end
-
- if add then
- indent_table.indents[#indent_table.indents + 1] = new_indent
- else
- if indent_table.indents[#indent_table.indents].name == new_indent.name then
- indent_table.indents[#indent_table.indents] = nil
- end
- end
-
- return indent_table
-end
-
-local function remove_indent(name)
- local function remove_indent_level(s, i, indent_table) -- luacheck: ignore s i
- indent_table = update_indent_table(indent_table, {name=name}, false)
- return true, indent_table
- end
-
- return Cg(Cmt(Cb("indent_info"), remove_indent_level), "indent_info")
-end
-
-local function process_starter_spacing(indent, spacing, minimum, left_strip_length)
- left_strip_length = left_strip_length or 0
-
- local count = 0
- local tab_value = 4 - (indent) % 4
-
- local code_started, minimum_found = false, false
- local code_start, minimum_remainder = "", ""
-
- local left_total_stripped = 0
- local full_remainder = ""
-
- if spacing ~= nil then
- for i = 1, #spacing do
- local character = spacing:sub(i, i)
-
- if character == "\t" then
- count = count + tab_value
- tab_value = 4
- elseif character == " " then
- count = count + 1
- tab_value = 4 - (1 - tab_value) % 4
- end
-
- if (left_strip_length ~= 0) then
- local possible_to_strip = math.min(count, left_strip_length)
- count = count - possible_to_strip
- left_strip_length = left_strip_length - possible_to_strip
- left_total_stripped = left_total_stripped + possible_to_strip
- else
- full_remainder = full_remainder .. character
- end
-
- if (minimum_found) then
- minimum_remainder = minimum_remainder .. character
- elseif (count >= minimum) then
- minimum_found = true
- minimum_remainder = minimum_remainder .. string.rep(" ", count - minimum)
- end
-
- if (code_started) then
- code_start = code_start .. character
- elseif (count >= minimum + 4) then
- code_started = true
- code_start = code_start .. string.rep(" ", count - (minimum + 4))
- end
- end
- end
-
- local remainder
- if (code_started) then
- remainder = code_start
- else
- remainder = string.rep(" ", count - minimum)
- end
-
- local is_minimum = count >= minimum
- return {
- is_code = code_started,
- remainder = remainder,
- left_total_stripped = left_total_stripped,
- is_minimum = is_minimum,
- minimum_remainder = minimum_remainder,
- total_length = count,
- full_remainder = full_remainder
- }
-end
-
-local function count_indent_tab_level(indent_table)
- local count = 0
- if not has_indents(indent_table) then
- return count
- end
-
- for i=1, #indent_table.indents do
- count = count + indent_table.indents[i].length
- end
- return count
-end
-
-local function total_delimiter_length(delimiter)
- local count = 0
- if type(delimiter) == "string" then return #delimiter end
- for _, value in pairs(delimiter) do
- count = count + total_delimiter_length(value)
- end
- return count
-end
-
-local function process_starter_indent(_, _, indent_table, starter, is_blank, indent_type, breakable)
- local last_trail = starter[1]
- local delimiter = starter[2]
- local raw_new_trail = starter[3]
-
- if indent_type == "bq" and not breakable then
- indent_table.ignore_blockquote_blank = true
- end
-
- if has_trail(indent_table) then
- local trail = indent_table.trail
- if trail.is_code then
- return false
- end
- last_trail = trail.remainder
- else
- local sp = process_starter_spacing(0, last_trail, 0, 0)
-
- if sp.is_code then
- return false
- end
- last_trail = sp.remainder
- end
-
- local preceding_indentation = count_indent_tab_level(indent_table) % 4
- local last_trail_length = #last_trail
- local delimiter_length = total_delimiter_length(delimiter)
-
- local total_indent_level = preceding_indentation + last_trail_length + delimiter_length
-
- local sp = {}
- if not is_blank then
- sp = process_starter_spacing(total_indent_level, raw_new_trail, 0, 1)
- end
-
- local del_trail_length = sp.left_total_stripped
- if is_blank then
- del_trail_length = 1
- elseif not sp.is_code then
- del_trail_length = del_trail_length + #sp.remainder
- end
-
- local indent_length = last_trail_length + delimiter_length + del_trail_length
- local new_indent_info = {name=indent_type, length=indent_length}
-
- indent_table = update_indent_table(indent_table, new_indent_info, true)
- indent_table = add_trail(indent_table, {is_code=sp.is_code, remainder=sp.remainder, total_length=sp.total_length,
- full_remainder=sp.full_remainder})
-
- return true, indent_table
-end
-
-local function decode_pattern(name)
- local delimeter = parsers.succeed
- if name == "bq" then
- delimeter = parsers.more
- end
-
- return C(parsers.optionalspace) * C(delimeter) * C(parsers.optionalspace) * Cp()
-end
-
-local function left_blank_starter(indent_table)
- local blank_starter_index
-
- if not has_indents(indent_table) then
- return
- end
-
- for i = #indent_table.indents,1,-1 do
- local value = indent_table.indents[i]
- if value.name == "li" then
- blank_starter_index = i
- else
- break
- end
- end
-
- return blank_starter_index
-end
-
-local function traverse_indent(s, i, indent_table, is_optional, is_blank, current_line_indents)
- local new_index = i
-
- local preceding_indentation = 0
- local current_trail = {}
-
- local blank_starter = left_blank_starter(indent_table)
-
- if current_line_indents == nil then
- current_line_indents = {}
- end
-
- for index = 1,#indent_table.indents do
- local value = indent_table.indents[index]
- local pattern = decode_pattern(value.name)
-
- -- match decoded pattern
- local new_indent_info = lpeg.match(Ct(pattern), s, new_index)
- if new_indent_info == nil then
- local blankline_end = lpeg.match(Ct(parsers.blankline * Cg(Cp(), "pos")), s, new_index)
- if is_optional or not indent_table.ignore_blockquote_blank or not blankline_end then
- return is_optional, new_index, current_trail, current_line_indents
- end
-
- return traverse_indent(s, tonumber(blankline_end.pos), indent_table, is_optional, is_blank, current_line_indents)
- end
-
- local raw_last_trail = new_indent_info[1]
- local delimiter = new_indent_info[2]
- local raw_new_trail = new_indent_info[3]
- local next_index = new_indent_info[4]
-
- local space_only = delimiter == ""
-
- -- check previous trail
- if not space_only and next(current_trail) == nil then
- local sp = process_starter_spacing(0, raw_last_trail, 0, 0)
- current_trail = {is_code=sp.is_code, remainder=sp.remainder, total_length=sp.total_length,
- full_remainder=sp.full_remainder}
- end
-
- if next(current_trail) ~= nil then
- if not space_only and current_trail.is_code then
- return is_optional, new_index, current_trail, current_line_indents
- end
- if current_trail.internal_remainder ~= nil then
- raw_last_trail = current_trail.internal_remainder
- end
- end
-
- local raw_last_trail_length = 0
- local delimiter_length = 0
-
- if not space_only then
- delimiter_length = #delimiter
- raw_last_trail_length = #raw_last_trail
- end
-
- local total_indent_level = preceding_indentation + raw_last_trail_length + delimiter_length
-
- local spacing_to_process
- local minimum = 0
- local left_strip_length = 0
-
- if not space_only then
- spacing_to_process = raw_new_trail
- left_strip_length = 1
- else
- spacing_to_process = raw_last_trail
- minimum = value.length
- end
-
- local sp = process_starter_spacing(total_indent_level, spacing_to_process, minimum, left_strip_length)
-
- if space_only and not sp.is_minimum then
- return is_optional or (is_blank and blank_starter <= index), new_index, current_trail, current_line_indents
- end
-
- local indent_length = raw_last_trail_length + delimiter_length + sp.left_total_stripped
-
- -- update info for the next pattern
- if not space_only then
- preceding_indentation = preceding_indentation + indent_length
- else
- preceding_indentation = preceding_indentation + value.length
- end
-
- current_trail = {is_code=sp.is_code, remainder=sp.remainder, internal_remainder=sp.minimum_remainder,
- total_length=sp.total_length, full_remainder=sp.full_remainder}
-
- current_line_indents[#current_line_indents + 1] = new_indent_info
- new_index = next_index
- end
-
- return true, new_index, current_trail, current_line_indents
-end
-
-local function check_trail(expect_code, is_code)
- return (expect_code and is_code) or (not expect_code and not is_code)
-end
-
-local function check_trail_joined(s, i, indent_table, spacing, expect_code, omit_remainder) -- luacheck: ignore s i
- local is_code
- local remainder
-
- if has_trail(indent_table) then
- local trail = indent_table.trail
- is_code = trail.is_code
- if is_code then
- remainder = trail.remainder
- else
- remainder = trail.full_remainder
- end
- else
- local sp = process_starter_spacing(0, spacing, 0, 0)
- is_code = sp.is_code
- if is_code then
- remainder = sp.remainder
- else
- remainder = sp.full_remainder
- end
- end
-
- local result = check_trail(expect_code, is_code)
- if omit_remainder then
- return result
- end
- return result, remainder
-end
-
-local function check_trail_length(s, i, indent_table, spacing, min, max) -- luacheck: ignore s i
- local trail
-
- if has_trail(indent_table) then
- trail = indent_table.trail
- else
- trail = process_starter_spacing(0, spacing, 0, 0)
- end
-
- local total_length = trail.total_length
- if total_length == nil then
- return false
- end
-
- return min <= total_length and total_length <= max
-end
-
-local function check_continuation_indentation(s, i, indent_table, is_optional, is_blank)
- if not has_indents(indent_table) then
- return true
- end
-
- local passes, new_index, current_trail, current_line_indents =
- traverse_indent(s, i, indent_table, is_optional, is_blank)
-
- if passes then
- indent_table.current_line_indents = current_line_indents
- indent_table = add_trail(indent_table, current_trail)
- return new_index, indent_table
- end
- return false
-end
-
-local function get_last_indent_name(indent_table)
- if has_indents(indent_table) then
- return indent_table.indents[#indent_table.indents].name
- end
-end
-
-local function remove_remainder_if_blank(indent_table, remainder)
- if get_last_indent_name(indent_table) == "li" then
- return ""
- end
- return remainder
-end
-
-local function check_trail_type(s, i, trail, spacing, trail_type) -- luacheck: ignore s i
- if trail == nil then
- trail = process_starter_spacing(0, spacing, 0, 0)
- end
-
- if trail_type == "non-code" then
- return check_trail(false, trail.is_code)
- end
- if trail_type == "code" then
- return check_trail(true, trail.is_code)
- end
- if trail_type == "full-code" then
- if (trail.is_code) then
- return i, trail.remainder
- end
- return i, ""
- end
- if trail_type == "full-any" then
- return i, trail.internal_remainder
- end
-end
-
-local function trail_freezing(s, i, indent_table, is_freezing) -- luacheck: ignore s i
- if is_freezing then
- if indent_table.is_trail_frozen then
- indent_table.trail = indent_table.frozen_trail
- else
- indent_table.frozen_trail = indent_table.trail
- indent_table.is_trail_frozen = true
- end
- else
- indent_table.frozen_trail = nil
- indent_table.is_trail_frozen = false
- end
- return true, indent_table
-end
-
-local function check_continuation_indentation_and_trail(s, i, indent_table, is_optional, is_blank, trail_type,
- reset_rem, omit_remainder)
- if not has_indents(indent_table) then
- local spacing, new_index = lpeg.match(C(parsers.spacechar^0) * Cp(), s, i)
- local result, remainder = check_trail_type(s, i, indent_table.trail, spacing, trail_type)
- if remainder == nil then
- if result then
- return new_index
- end
- return false
- end
- if result then
- return new_index, remainder
- end
- return false
- end
-
- local passes, new_index, current_trail = traverse_indent(s, i, indent_table, is_optional, is_blank)
-
- if passes then
- local spacing
- if current_trail == nil then
- local newer_spacing, newer_index = lpeg.match(C(parsers.spacechar^0) * Cp(), s, i)
- current_trail = process_starter_spacing(0, newer_spacing, 0, 0)
- new_index = newer_index
- spacing = newer_spacing
- else
- spacing = current_trail.remainder
- end
- local result, remainder = check_trail_type(s, new_index, current_trail, spacing, trail_type)
- if remainder == nil or omit_remainder then
- if result then
- return new_index
- end
- return false
- end
-
- if is_blank and reset_rem then
- remainder = remove_remainder_if_blank(indent_table, remainder)
- end
- if result then
- return new_index, remainder
- end
- return false
- end
- return false
-end
-
-parsers.check_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(false), check_trail_joined)
-
-parsers.check_trail_no_rem = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(false) * Cc(true), check_trail_joined)
-
-parsers.check_code_trail = Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(true), check_trail_joined)
-
-parsers.check_trail_length_range = function(min, max)
- return Cmt(Cb("indent_info") * C(parsers.spacechar^0) * Cc(min) * Cc(max), check_trail_length)
-end
-
-parsers.check_trail_length = function(n)
- return parsers.check_trail_length_range(n, n)
-end
-
-parsers.freeze_trail = Cg(Cmt(Cb("indent_info") * Cc(true), trail_freezing), "indent_info")
-
-parsers.unfreeze_trail = Cg(Cmt(Cb("indent_info") * Cc(false), trail_freezing), "indent_info")
-
-parsers.check_minimal_indent = Cmt(Cb("indent_info") * Cc(false), check_continuation_indentation)
-
-parsers.check_optional_indent = Cmt(Cb("indent_info") * Cc(true), check_continuation_indentation)
-
-parsers.check_minimal_blank_indent = Cmt(Cb("indent_info") * Cc(false) * Cc(true), check_continuation_indentation)
-
-
-parsers.check_minimal_indent_and_trail = Cmt( Cb("indent_info")
- * Cc(false) * Cc(false) * Cc("non-code") * Cc(true),
- check_continuation_indentation_and_trail)
-
-parsers.check_minimal_indent_and_code_trail = Cmt( Cb("indent_info")
- * Cc(false) * Cc(false) * Cc("code") * Cc(false),
- check_continuation_indentation_and_trail)
-
-parsers.check_minimal_blank_indent_and_full_code_trail = Cmt( Cb("indent_info")
- * Cc(false) * Cc(true) * Cc("full-code") * Cc(true),
- check_continuation_indentation_and_trail)
-
-parsers.check_minimal_indent_and_any_trail = Cmt( Cb("indent_info")
- * Cc(false) * Cc(false) * Cc("full-any") * Cc(true) * Cc(false),
- check_continuation_indentation_and_trail)
-
-parsers.check_minimal_blank_indent_and_any_trail = Cmt( Cb("indent_info")
- * Cc(false) * Cc(true) * Cc("full-any") * Cc(true) * Cc(false),
- check_continuation_indentation_and_trail)
-
-parsers.check_minimal_blank_indent_and_any_trail_no_rem = Cmt( Cb("indent_info")
- * Cc(false) * Cc(true) * Cc("full-any") * Cc(true) * Cc(true),
- check_continuation_indentation_and_trail)
-
-parsers.check_optional_indent_and_any_trail = Cmt( Cb("indent_info")
- * Cc(true) * Cc(false) * Cc("full-any") * Cc(true) * Cc(false),
- check_continuation_indentation_and_trail)
-
-parsers.check_optional_blank_indent_and_any_trail = Cmt( Cb("indent_info")
- * Cc(true) * Cc(true) * Cc("full-any") * Cc(true) * Cc(false),
- check_continuation_indentation_and_trail)
-
-
-parsers.spnlc_noexc = parsers.optionalspace
- * (parsers.newline * parsers.check_minimal_indent_and_any_trail)^-1
-
-parsers.spnlc = parsers.optionalspace
- * (V("EndlineNoSub"))^-1
-
-parsers.spnlc_sep = parsers.optionalspace * V("EndlineNoSub")
- + parsers.spacechar^1
-
-parsers.only_blank = parsers.spacechar^0 * (parsers.newline + parsers.eof)
-
-parsers.commented_line_letter = parsers.linechar
- + parsers.newline
- - parsers.backslash
- - parsers.percent
-parsers.commented_line = Cg(Cc(""), "backslashes")
- * ((#(parsers.commented_line_letter
- - parsers.newline)
- * Cb("backslashes")
- * Cs(parsers.commented_line_letter
- - parsers.newline)^1 -- initial
- * Cg(Cc(""), "backslashes"))
- + #(parsers.backslash * parsers.backslash)
- * Cg((parsers.backslash -- even backslash
- * parsers.backslash)^1, "backslashes")
- + (parsers.backslash
- * (#parsers.percent
- * Cb("backslashes")
- / function(backslashes)
- return string.rep("\\", #backslashes / 2)
- end
- * C(parsers.percent)
- + #parsers.commented_line_letter
- * Cb("backslashes")
- * Cc("\\")
- * C(parsers.commented_line_letter))
- * Cg(Cc(""), "backslashes")))^0
- * (#parsers.percent
- * Cb("backslashes")
- / function(backslashes)
- return string.rep("\\", #backslashes / 2)
- end
- * ((parsers.percent -- comment
- * parsers.line
- * #parsers.blankline) -- blank line
- / "\n"
- + parsers.percent -- comment
- * parsers.line
- * parsers.optionalspace) -- leading tabs and spaces
- + #(parsers.newline)
- * Cb("backslashes")
- * C(parsers.newline))
-
-parsers.chunk = parsers.line * (parsers.optionallyindentedline
- - parsers.blankline)^0
-
-parsers.attribute_key_char = parsers.alphanumeric + S("-_:.")
-parsers.attribute_raw_char = parsers.alphanumeric + S("-_")
-parsers.attribute_key = (parsers.attribute_key_char
- - parsers.dash - parsers.digit)
- * parsers.attribute_key_char^0
-parsers.attribute_value = ( (parsers.dquote / "")
- * (parsers.anyescaped - parsers.dquote)^0
- * (parsers.dquote / ""))
- + ( (parsers.squote / "")
- * (parsers.anyescaped - parsers.squote)^0
- * (parsers.squote / ""))
- + ( parsers.anyescaped - parsers.dquote - parsers.rbrace
- - parsers.space)^0
-parsers.attribute_identifier = parsers.attribute_key_char^1
-parsers.attribute_classname = parsers.letter
- * parsers.attribute_key_char^0
-parsers.attribute_raw = parsers.attribute_raw_char^1
-
-parsers.attribute = (parsers.dash * Cc(".unnumbered"))
- + C( parsers.hash
- * parsers.attribute_identifier)
- + C( parsers.period
- * parsers.attribute_classname)
- + Cs( parsers.attribute_key
- * parsers.optionalspace * parsers.equal * parsers.optionalspace
- * parsers.attribute_value)
-parsers.attributes = parsers.lbrace
- * parsers.optionalspace
- * parsers.attribute
- * (parsers.spacechar^1
- * parsers.attribute)^0
- * parsers.optionalspace
- * parsers.rbrace
-
-parsers.raw_attribute = parsers.lbrace
- * parsers.optionalspace
- * parsers.equal
- * C(parsers.attribute_raw)
- * parsers.optionalspace
- * parsers.rbrace
-
--- block followed by 0 or more optionally
--- indented blocks with first line indented.
-parsers.indented_blocks = function(bl)
- return Cs( bl
- * (parsers.blankline^1 * parsers.indent * -parsers.blankline * bl)^0
- * (parsers.blankline^1 + parsers.eof) )
-end
-local function repeat_between(pattern, min, max)
- return -pattern^(max + 1) * pattern^min
-end
-
-parsers.hexentity = parsers.ampersand * parsers.hash * C(S("Xx"))
- * C(repeat_between(parsers.hexdigit, 1, 6)) * parsers.semicolon
-parsers.decentity = parsers.ampersand * parsers.hash
- * C(repeat_between(parsers.digit, 1, 7)) * parsers.semicolon
-parsers.tagentity = parsers.ampersand * C(parsers.alphanumeric^1)
- * parsers.semicolon
-
-parsers.html_entities = parsers.hexentity / entities.hex_entity_with_x_char
- + parsers.decentity / entities.dec_entity
- + parsers.tagentity / entities.char_entity
-parsers.bullet = function(bullet_char, interrupting)
- local allowed_end
- if interrupting then
- allowed_end = C(parsers.spacechar^1) * #parsers.linechar
- else
- allowed_end = C(parsers.spacechar^1) + #(parsers.newline + parsers.eof)
- end
- return parsers.check_trail
- * Ct(C(bullet_char) * Cc(""))
- * allowed_end
-end
-
-local function tickbox(interior)
- return parsers.optionalspace * parsers.lbracket
- * interior * parsers.rbracket * parsers.spacechar^1
-end
-
-parsers.ticked_box = tickbox(S("xX")) * Cc(1.0)
-parsers.halfticked_box = tickbox(S("./")) * Cc(0.5)
-parsers.unticked_box = tickbox(parsers.spacechar^1) * Cc(0.0)
-
-parsers.openticks = Cg(parsers.backtick^1, "ticks")
-
-local function captures_equal_length(_,i,a,b)
- return #a == #b and i
-end
-
-parsers.closeticks = Cmt(C(parsers.backtick^1)
- * Cb("ticks"), captures_equal_length)
-
-parsers.intickschar = (parsers.any - S("\n\r`"))
- + V("NoSoftLineBreakEndline")
- + (parsers.backtick^1 - parsers.closeticks)
-
-local function process_inticks(s)
- s = s:gsub("\n", " ")
- s = s:gsub("^ (.*) $", "%1")
- return s
-end
-
-parsers.inticks = parsers.openticks
- * C(parsers.space^0)
- * parsers.closeticks
- + parsers.openticks
- * Cs(Cs(parsers.intickschar^0) / process_inticks)
- * parsers.closeticks
-
--- case-insensitive match (we assume s is lowercase). must be single byte encoding
-parsers.keyword_exact = function(s)
- local parser = P(0)
- for i=1,#s do
- local c = s:sub(i,i)
- local m = c .. upper(c)
- parser = parser * S(m)
- end
- return parser
-end
-
-parsers.special_block_keyword =
- parsers.keyword_exact("pre") +
- parsers.keyword_exact("script") +
- parsers.keyword_exact("style") +
- parsers.keyword_exact("textarea")
-
-parsers.block_keyword =
- parsers.keyword_exact("address") +
- parsers.keyword_exact("article") +
- parsers.keyword_exact("aside") +
- parsers.keyword_exact("base") +
- parsers.keyword_exact("basefont") +
- parsers.keyword_exact("blockquote") +
- parsers.keyword_exact("body") +
- parsers.keyword_exact("caption") +
- parsers.keyword_exact("center") +
- parsers.keyword_exact("col") +
- parsers.keyword_exact("colgroup") +
- parsers.keyword_exact("dd") +
- parsers.keyword_exact("details") +
- parsers.keyword_exact("dialog") +
- parsers.keyword_exact("dir") +
- parsers.keyword_exact("div") +
- parsers.keyword_exact("dl") +
- parsers.keyword_exact("dt") +
- parsers.keyword_exact("fieldset") +
- parsers.keyword_exact("figcaption") +
- parsers.keyword_exact("figure") +
- parsers.keyword_exact("footer") +
- parsers.keyword_exact("form") +
- parsers.keyword_exact("frame") +
- parsers.keyword_exact("frameset") +
- parsers.keyword_exact("h1") +
- parsers.keyword_exact("h2") +
- parsers.keyword_exact("h3") +
- parsers.keyword_exact("h4") +
- parsers.keyword_exact("h5") +
- parsers.keyword_exact("h6") +
- parsers.keyword_exact("head") +
- parsers.keyword_exact("header") +
- parsers.keyword_exact("hr") +
- parsers.keyword_exact("html") +
- parsers.keyword_exact("iframe") +
- parsers.keyword_exact("legend") +
- parsers.keyword_exact("li") +
- parsers.keyword_exact("link") +
- parsers.keyword_exact("main") +
- parsers.keyword_exact("menu") +
- parsers.keyword_exact("menuitem") +
- parsers.keyword_exact("nav") +
- parsers.keyword_exact("noframes") +
- parsers.keyword_exact("ol") +
- parsers.keyword_exact("optgroup") +
- parsers.keyword_exact("option") +
- parsers.keyword_exact("p") +
- parsers.keyword_exact("param") +
- parsers.keyword_exact("section") +
- parsers.keyword_exact("source") +
- parsers.keyword_exact("summary") +
- parsers.keyword_exact("table") +
- parsers.keyword_exact("tbody") +
- parsers.keyword_exact("td") +
- parsers.keyword_exact("tfoot") +
- parsers.keyword_exact("th") +
- parsers.keyword_exact("thead") +
- parsers.keyword_exact("title") +
- parsers.keyword_exact("tr") +
- parsers.keyword_exact("track") +
- parsers.keyword_exact("ul")
-
--- end conditions
-parsers.html_blankline_end_condition = parsers.linechar^0
- * ( parsers.newline
- * (parsers.check_minimal_blank_indent_and_any_trail
- * #parsers.blankline
- + parsers.check_minimal_indent_and_any_trail)
- * parsers.linechar^1)^0
- * (parsers.newline^-1 / "")
-
-local function remove_trailing_blank_lines(s)
- return s:gsub("[\n\r]+%s*$", "")
-end
-
-parsers.html_until_end = function(end_marker)
- return Cs(Cs((parsers.newline
- * (parsers.check_minimal_blank_indent_and_any_trail
- * #parsers.blankline
- + parsers.check_minimal_indent_and_any_trail)
- + parsers.linechar - end_marker)^0
- * parsers.linechar^0 * parsers.newline^-1)
- / remove_trailing_blank_lines)
-end
-
--- attributes
-parsers.html_attribute_spacing = parsers.optionalspace
- * V("NoSoftLineBreakEndline")
- * parsers.optionalspace
- + parsers.spacechar^1
-
-parsers.html_attribute_name = (parsers.letter + parsers.colon + parsers.underscore)
- * (parsers.alphanumeric + parsers.colon + parsers.underscore
- + parsers.period + parsers.dash)^0
-
-parsers.html_attribute_value = parsers.squote
- * (parsers.linechar - parsers.squote)^0
- * parsers.squote
- + parsers.dquote
- * (parsers.linechar - parsers.dquote)^0
- * parsers.dquote
- + ( parsers.any - parsers.spacechar - parsers.newline
- - parsers.dquote - parsers.squote - parsers.backtick
- - parsers.equal - parsers.less - parsers.more)^1
-
-parsers.html_inline_attribute_value = parsers.squote
- * (V("NoSoftLineBreakEndline")
- + parsers.any
- - parsers.blankline^2
- - parsers.squote)^0
- * parsers.squote
- + parsers.dquote
- * (V("NoSoftLineBreakEndline")
- + parsers.any
- - parsers.blankline^2
- - parsers.dquote)^0
- * parsers.dquote
- + (parsers.any - parsers.spacechar - parsers.newline
- - parsers.dquote - parsers.squote - parsers.backtick
- - parsers.equal - parsers.less - parsers.more)^1
-
-parsers.html_attribute_value_specification = parsers.optionalspace
- * parsers.equal
- * parsers.optionalspace
- * parsers.html_attribute_value
-
-parsers.html_spnl = parsers.optionalspace
- * (V("NoSoftLineBreakEndline") * parsers.optionalspace)^-1
-
-parsers.html_inline_attribute_value_specification = parsers.html_spnl
- * parsers.equal
- * parsers.html_spnl
- * parsers.html_inline_attribute_value
-
-parsers.html_attribute = parsers.html_attribute_spacing
- * parsers.html_attribute_name
- * parsers.html_inline_attribute_value_specification^-1
-
-parsers.html_non_newline_attribute = parsers.spacechar^1
- * parsers.html_attribute_name
- * parsers.html_attribute_value_specification^-1
-
-parsers.nested_breaking_blank = parsers.newline
- * parsers.check_minimal_blank_indent
- * parsers.blankline
-
-parsers.html_comment_start = P("<!--")
-
-parsers.html_comment_end = P("-->")
-
-parsers.html_comment = Cs( parsers.html_comment_start
- * parsers.html_until_end(parsers.html_comment_end))
-
-parsers.html_inline_comment = (parsers.html_comment_start / "")
- * -P(">") * -P("->")
- * Cs((V("NoSoftLineBreakEndline") + parsers.any
- - parsers.nested_breaking_blank - parsers.html_comment_end)^0)
- * (parsers.html_comment_end / "")
-
-parsers.html_cdatasection_start = P("<![CDATA[")
-
-parsers.html_cdatasection_end = P("]]>")
-
-parsers.html_cdatasection = Cs( parsers.html_cdatasection_start
- * parsers.html_until_end(parsers.html_cdatasection_end))
-
-parsers.html_inline_cdatasection = parsers.html_cdatasection_start
- * Cs(V("NoSoftLineBreakEndline") + parsers.any
- - parsers.nested_breaking_blank - parsers.html_cdatasection_end)^0
- * parsers.html_cdatasection_end
-
-parsers.html_declaration_start = P("<!") * parsers.letter
-
-parsers.html_declaration_end = P(">")
-
-parsers.html_declaration = Cs( parsers.html_declaration_start
- * parsers.html_until_end(parsers.html_declaration_end))
-
-parsers.html_inline_declaration = parsers.html_declaration_start
- * Cs(V("NoSoftLineBreakEndline") + parsers.any
- - parsers.nested_breaking_blank - parsers.html_declaration_end)^0
- * parsers.html_declaration_end
-
-parsers.html_instruction_start = P("<?")
-
-parsers.html_instruction_end = P("?>")
-
-parsers.html_instruction = Cs( parsers.html_instruction_start
- * parsers.html_until_end(parsers.html_instruction_end))
-
-parsers.html_inline_instruction = parsers.html_instruction_start
- * Cs(V("NoSoftLineBreakEndline") + parsers.any
- - parsers.nested_breaking_blank - parsers.html_instruction_end)^0
- * parsers.html_instruction_end
-
-parsers.html_blankline = parsers.newline
- * parsers.optionalspace
- * parsers.newline
-
-parsers.html_tag_start = parsers.less
-
-parsers.html_tag_closing_start = parsers.less
- * parsers.slash
-
-parsers.html_tag_end = parsers.html_spnl
- * parsers.more
-
-parsers.html_empty_tag_end = parsers.html_spnl
- * parsers.slash
- * parsers.more
-
--- opening tags
-parsers.html_any_open_inline_tag = parsers.html_tag_start
- * parsers.keyword
- * parsers.html_attribute^0
- * parsers.html_tag_end
-
-parsers.html_any_open_tag = parsers.html_tag_start
- * parsers.keyword
- * parsers.html_non_newline_attribute^0
- * parsers.html_tag_end
-
-parsers.html_open_tag = parsers.html_tag_start
- * parsers.block_keyword
- * parsers.html_attribute^0
- * parsers.html_tag_end
-
-parsers.html_open_special_tag = parsers.html_tag_start
- * parsers.special_block_keyword
- * parsers.html_attribute^0
- * parsers.html_tag_end
-
--- incomplete tags
-parsers.incomplete_tag_following = parsers.spacechar
- + parsers.more
- + parsers.slash * parsers.more
- + #(parsers.newline + parsers.eof)
-
-parsers.incomplete_special_tag_following = parsers.spacechar
- + parsers.more
- + #(parsers.newline + parsers.eof)
-
-parsers.html_incomplete_open_tag = parsers.html_tag_start
- * parsers.block_keyword
- * parsers.incomplete_tag_following
-
-parsers.html_incomplete_open_special_tag = parsers.html_tag_start
- * parsers.special_block_keyword
- * parsers.incomplete_special_tag_following
-
-parsers.html_incomplete_close_tag = parsers.html_tag_closing_start
- * parsers.block_keyword
- * parsers.incomplete_tag_following
-
-parsers.html_incomplete_close_special_tag = parsers.html_tag_closing_start
- * parsers.special_block_keyword
- * parsers.incomplete_tag_following
-
--- closing tags
-parsers.html_close_tag = parsers.html_tag_closing_start
- * parsers.block_keyword
- * parsers.html_tag_end
-
-parsers.html_any_close_tag = parsers.html_tag_closing_start
- * parsers.keyword
- * parsers.html_tag_end
-
-parsers.html_close_special_tag = parsers.html_tag_closing_start
- * parsers.special_block_keyword
- * parsers.html_tag_end
-
--- empty tags
-parsers.html_any_empty_inline_tag = parsers.html_tag_start
- * parsers.keyword
- * parsers.html_attribute^0
- * parsers.html_empty_tag_end
-
-parsers.html_any_empty_tag = parsers.html_tag_start
- * parsers.keyword
- * parsers.html_non_newline_attribute^0
- * parsers.optionalspace
- * parsers.slash
- * parsers.more
-
-parsers.html_empty_tag = parsers.html_tag_start
- * parsers.block_keyword
- * parsers.html_attribute^0
- * parsers.html_empty_tag_end
-
-parsers.html_empty_special_tag = parsers.html_tag_start
- * parsers.special_block_keyword
- * parsers.html_attribute^0
- * parsers.html_empty_tag_end
-
-parsers.html_incomplete_blocks = parsers.html_incomplete_open_tag
- + parsers.html_incomplete_open_special_tag
- + parsers.html_incomplete_close_tag
-
--- parse special html blocks
-parsers.html_blankline_ending_special_block_opening = (parsers.html_close_special_tag
- + parsers.html_empty_special_tag)
- * #(parsers.optionalspace
- * (parsers.newline + parsers.eof))
-
-parsers.html_blankline_ending_special_block = parsers.html_blankline_ending_special_block_opening
- * parsers.html_blankline_end_condition
-
-parsers.html_special_block_opening = parsers.html_incomplete_open_special_tag
- - parsers.html_empty_special_tag
-
-parsers.html_closing_special_block = parsers.html_special_block_opening
- * parsers.html_until_end(parsers.html_close_special_tag)
-
-parsers.html_special_block = parsers.html_blankline_ending_special_block
- + parsers.html_closing_special_block
-
--- parse html blocks
-parsers.html_block_opening = parsers.html_incomplete_open_tag
- + parsers.html_incomplete_close_tag
-
-parsers.html_block = parsers.html_block_opening
- * parsers.html_blankline_end_condition
-
--- parse any html blocks
-parsers.html_any_block_opening = (parsers.html_any_open_tag
- + parsers.html_any_close_tag
- + parsers.html_any_empty_tag)
- * #(parsers.optionalspace * (parsers.newline + parsers.eof))
-
-parsers.html_any_block = parsers.html_any_block_opening
- * parsers.html_blankline_end_condition
-
-parsers.html_inline_comment_full = parsers.html_comment_start
- * -P(">") * -P("->")
- * Cs((V("NoSoftLineBreakEndline") + parsers.any - P("--")
- - parsers.nested_breaking_blank - parsers.html_comment_end)^0)
- * parsers.html_comment_end
-
-parsers.html_inline_tags = parsers.html_inline_comment_full
- + parsers.html_any_empty_inline_tag
- + parsers.html_inline_instruction
- + parsers.html_inline_cdatasection
- + parsers.html_inline_declaration
- + parsers.html_any_open_inline_tag
- + parsers.html_any_close_tag
-
-parsers.urlchar = parsers.anyescaped
- - parsers.newline
- - parsers.more
-
-parsers.auto_link_scheme_part = parsers.alphanumeric
- + parsers.plus
- + parsers.period
- + parsers.dash
-
-parsers.auto_link_scheme = parsers.letter
- * parsers.auto_link_scheme_part
- * parsers.auto_link_scheme_part^-30
-
-parsers.absolute_uri = parsers.auto_link_scheme * parsers.colon
- * (parsers.any - parsers.spacing - parsers.less - parsers.more)^0
-
-parsers.printable_characters = S(".!#$%&'*+/=?^_`{|}~-")
-
-parsers.email_address_local_part_char = parsers.alphanumeric
- + parsers.printable_characters
-
-parsers.email_address_local_part = parsers.email_address_local_part_char^1
-
-parsers.email_address_dns_label = parsers.alphanumeric
- * (parsers.alphanumeric + parsers.dash)^-62
- * B(parsers.alphanumeric)
-
-parsers.email_address_domain = parsers.email_address_dns_label
- * (parsers.period * parsers.email_address_dns_label)^0
-
-parsers.email_address = parsers.email_address_local_part
- * parsers.at
- * parsers.email_address_domain
-
-parsers.auto_link_url = parsers.less
- * C(parsers.absolute_uri)
- * parsers.more
-
-parsers.auto_link_email = parsers.less
- * C(parsers.email_address)
- * parsers.more
-
-parsers.auto_link_relative_reference = parsers.less
- * C(parsers.urlchar^1)
- * parsers.more
-
-parsers.autolink = parsers.auto_link_url
- + parsers.auto_link_email
-
--- content in balanced brackets, parentheses, or quotes:
-parsers.bracketed = P{ parsers.lbracket
- * (( parsers.backslash / "" * parsers.rbracket
- + parsers.any - (parsers.lbracket
- + parsers.rbracket
- + parsers.blankline^2)
- ) + V(1))^0
- * parsers.rbracket }
-
-parsers.inparens = P{ parsers.lparent
- * ((parsers.anyescaped - (parsers.lparent
- + parsers.rparent
- + parsers.blankline^2)
- ) + V(1))^0
- * parsers.rparent }
-
-parsers.squoted = P{ parsers.squote * parsers.alphanumeric
- * ((parsers.anyescaped - (parsers.squote
- + parsers.blankline^2)
- ) + V(1))^0
- * parsers.squote }
-
-parsers.dquoted = P{ parsers.dquote * parsers.alphanumeric
- * ((parsers.anyescaped - (parsers.dquote
- + parsers.blankline^2)
- ) + V(1))^0
- * parsers.dquote }
-
-parsers.link_text = parsers.lbracket
- * Cs((parsers.alphanumeric^1
- + parsers.bracketed
- + parsers.inticks
- + parsers.autolink
- + V("InlineHtml")
- + ( parsers.backslash * parsers.backslash)
- + ( parsers.backslash * (parsers.lbracket + parsers.rbracket)
- + V("NoSoftLineBreakSpace")
- + V("NoSoftLineBreakEndline")
- + (parsers.any
- - (parsers.newline + parsers.lbracket + parsers.rbracket + parsers.blankline^2))))^0)
- * parsers.rbracket
-
-parsers.link_label = parsers.lbracket
- * -#(parsers.sp * parsers.rbracket)
- * #((parsers.any - parsers.rbracket)^-999 * parsers.rbracket)
- * Cs((parsers.alphanumeric^1
- + parsers.inticks
- + parsers.autolink
- + V("InlineHtml")
- + ( parsers.backslash * parsers.backslash)
- + ( parsers.backslash * (parsers.lbracket + parsers.rbracket)
- + V("NoSoftLineBreakSpace")
- + V("NoSoftLineBreakEndline")
- + (parsers.any
- - (parsers.newline + parsers.lbracket + parsers.rbracket + parsers.blankline^2))))^1)
- * parsers.rbracket
-
-parsers.inparens_url = P{ parsers.lparent
- * ((parsers.anyescaped - (parsers.lparent
- + parsers.rparent
- + parsers.spacing)
- ) + V(1))^0
- * parsers.rparent }
-
--- url for markdown links, allowing nested brackets:
-parsers.url = parsers.less * Cs((parsers.anyescaped
- - parsers.newline
- - parsers.less
- - parsers.more)^0)
- * parsers.more
- + -parsers.less
- * Cs((parsers.inparens_url + (parsers.anyescaped
- - parsers.spacing
- - parsers.lparent
- - parsers.rparent))^1)
-
--- quoted text:
-parsers.title_s = parsers.squote
- * Cs((parsers.html_entities
- + V("NoSoftLineBreakSpace")
- + V("NoSoftLineBreakEndline")
- + (parsers.anyescaped - parsers.newline - parsers.squote - parsers.blankline^2))^0)
- * parsers.squote
-
-parsers.title_d = parsers.dquote
- * Cs((parsers.html_entities
- + V("NoSoftLineBreakSpace")
- + V("NoSoftLineBreakEndline")
- + (parsers.anyescaped - parsers.newline - parsers.dquote - parsers.blankline^2))^0)
- * parsers.dquote
-
-parsers.title_p = parsers.lparent
- * Cs((parsers.html_entities
- + V("NoSoftLineBreakSpace")
- + V("NoSoftLineBreakEndline")
- + (parsers.anyescaped - parsers.newline - parsers.lparent - parsers.rparent
- - parsers.blankline^2))^0)
- * parsers.rparent
-
-parsers.title = parsers.title_d + parsers.title_s + parsers.title_p
-
-parsers.optionaltitle
- = parsers.spnlc * parsers.title * parsers.spacechar^0
- + Cc("")
-
--- parse a reference definition: [foo]: /bar "title"
-parsers.define_reference_parser = (parsers.check_trail / "") * parsers.link_label * parsers.colon
- * parsers.spnlc * parsers.url
- * ( parsers.spnlc_sep * parsers.title * parsers.only_blank
- + Cc("") * parsers.only_blank)
-parsers.Inline = V("Inline")
-
--- parse many p between starter and ender
-parsers.between = function(p, starter, ender)
- local ender2 = B(parsers.nonspacechar) * ender
- return (starter * #parsers.nonspacechar * Ct(p * (p - ender2)^0) * ender2)
-end
-
-parsers.lineof = function(c)
- return (parsers.check_trail_no_rem * (P(c) * parsers.optionalspace)^3
- * (parsers.newline + parsers.eof))
-end
-
-parsers.thematic_break_lines = parsers.lineof(parsers.asterisk)
- + parsers.lineof(parsers.dash)
- + parsers.lineof(parsers.underscore)
--- parse Atx heading start and return level
-parsers.heading_start = #parsers.hash * C(parsers.hash^-6)
- * -parsers.hash / length
-
--- parse setext header ending and return level
-parsers.heading_level = parsers.nonindentspace * parsers.equal^1 * parsers.optionalspace * #parsers.newline * Cc(1)
- + parsers.nonindentspace * parsers.dash^1 * parsers.optionalspace * #parsers.newline * Cc(2)
-
-local function strip_atx_end(s)
- return s:gsub("%s+#*%s*\n$","")
-end
-
-parsers.atx_heading = parsers.check_trail_no_rem
- * Cg(parsers.heading_start, "level")
- * (C( parsers.optionalspace
- * parsers.hash^0
- * parsers.optionalspace
- * parsers.newline)
- + parsers.spacechar^1
- * C(parsers.line))
-M.reader = {}
-function M.reader.new(writer, options)
- local self = {}
- self.writer = writer
- self.options = options
- self.parsers = {}
- (function(parsers)
- setmetatable(self.parsers, {
- __index = function (_, key)
- return parsers[key]
- end
- })
- end)(parsers)
- local parsers = self.parsers
- function self.normalize_tag(tag)
- tag = util.rope_to_string(tag)
- tag = tag:gsub("[ \n\r\t]+", " ")
- tag = tag:gsub("^ ", ""):gsub(" $", "")
- tag = uni_algos.case.casefold(tag, true, false)
- return tag
- end
- local function iterlines(s, f)
- local rope = lpeg.match(Ct((parsers.line / f)^1), s)
- return util.rope_to_string(rope)
- end
- if options.preserveTabs then
- self.expandtabs = function(s) return s end
- else
- self.expandtabs = function(s)
- if s:find("\t") then
- return iterlines(s, util.expand_tabs_in_line)
- else
- return s
- end
- end
- end
- self.parser_functions = {}
- self.create_parser = function(name, grammar, toplevel)
- self.parser_functions[name] = function(str)
- if toplevel and options.stripIndent then
- local min_prefix_length, min_prefix = nil, ''
- str = iterlines(str, function(line)
- if lpeg.match(parsers.nonemptyline, line) == nil then
- return line
- end
- line = util.expand_tabs_in_line(line)
- local prefix = lpeg.match(C(parsers.optionalspace), line)
- local prefix_length = #prefix
- local is_shorter = min_prefix_length == nil
- is_shorter = is_shorter or prefix_length < min_prefix_length
- if is_shorter then
- min_prefix_length, min_prefix = prefix_length, prefix
- end
- return line
- end)
- str = str:gsub('^' .. min_prefix, '')
- end
- if toplevel and (options.texComments or options.hybrid) then
- str = lpeg.match(Ct(parsers.commented_line^1), str)
- str = util.rope_to_string(str)
- end
- local res = lpeg.match(grammar(), str)
- if res == nil then
- error(format("%s failed on:\n%s", name, str:sub(1,20)))
- else
- return res
- end
- end
- end
-
- self.create_parser("parse_blocks",
- function()
- return parsers.blocks
- end, true)
-
- self.create_parser("parse_blocks_nested",
- function()
- return parsers.blocks_nested
- end, false)
-
- self.create_parser("parse_inlines",
- function()
- return parsers.inlines
- end, false)
-
- self.create_parser("parse_inlines_no_inline_note",
- function()
- return parsers.inlines_no_inline_note
- end, false)
-
- self.create_parser("parse_inlines_no_html",
- function()
- return parsers.inlines_no_html
- end, false)
-
- self.create_parser("parse_inlines_nbsp",
- function()
- return parsers.inlines_nbsp
- end, false)
- self.create_parser("parse_inlines_no_link_or_emphasis",
- function()
- return parsers.inlines_no_link_or_emphasis
- end, false)
- parsers.minimally_indented_blankline = parsers.check_minimal_indent * (parsers.blankline / "")
-
- parsers.minimally_indented_block = parsers.check_minimal_indent * V("Block")
-
- parsers.minimally_indented_block_or_paragraph = parsers.check_minimal_indent * V("BlockOrParagraph")
-
- parsers.minimally_indented_paragraph = parsers.check_minimal_indent * V("Paragraph")
-
- parsers.minimally_indented_plain = parsers.check_minimal_indent * V("Plain")
-
- parsers.minimally_indented_par_or_plain = parsers.minimally_indented_paragraph
- + parsers.minimally_indented_plain
-
- parsers.minimally_indented_par_or_plain_no_blank = parsers.minimally_indented_par_or_plain
- - parsers.minimally_indented_blankline
-
- parsers.minimally_indented_ref = parsers.check_minimal_indent * V("Reference")
-
- parsers.minimally_indented_blank = parsers.check_minimal_indent * V("Blank")
-
- parsers.conditionally_indented_blankline = parsers.check_minimal_blank_indent * (parsers.blankline / "")
-
- parsers.minimally_indented_ref_or_block = parsers.minimally_indented_ref
- + parsers.minimally_indented_block
- - parsers.minimally_indented_blankline
-
- parsers.minimally_indented_ref_or_block_or_par = parsers.minimally_indented_ref
- + parsers.minimally_indented_block_or_paragraph
- - parsers.minimally_indented_blankline
-
-
- parsers.separator_loop = function(separated_block, paragraph, block_separator, paragraph_separator)
- return separated_block
- + block_separator
- * paragraph
- * separated_block
- + paragraph_separator
- * paragraph
- end
-
- parsers.create_loop_body_pair = function(separated_block, paragraph, block_separator, paragraph_separator)
- return {
- block = parsers.separator_loop(separated_block, paragraph, block_separator, block_separator),
- par = parsers.separator_loop(separated_block, paragraph, block_separator, paragraph_separator)
- }
- end
-
- parsers.block_sep_group = function(blank)
- return blank^0 * parsers.eof
- + ( blank^2 / writer.paragraphsep
- + blank^0 / writer.interblocksep
- )
- end
-
- parsers.par_sep_group = function(blank)
- return blank^0 * parsers.eof
- + blank^0 / writer.paragraphsep
- end
-
- parsers.sep_group_no_output = function(blank)
- return blank^0 * parsers.eof
- + blank^0
- end
-
- parsers.content_blank = parsers.minimally_indented_blankline
-
- parsers.ref_or_block_separated = parsers.sep_group_no_output(parsers.content_blank)
- * ( parsers.minimally_indented_ref
- - parsers.content_blank)
- + parsers.block_sep_group(parsers.content_blank)
- * ( parsers.minimally_indented_block
- - parsers.content_blank)
-
- parsers.loop_body_pair =
- parsers.create_loop_body_pair(parsers.ref_or_block_separated,
- parsers.minimally_indented_par_or_plain_no_blank,
- parsers.block_sep_group(parsers.content_blank),
- parsers.par_sep_group(parsers.content_blank))
-
- parsers.content_loop = ( V("Block")
- * parsers.loop_body_pair.block^0
- + (V("Paragraph") + V("Plain"))
- * parsers.ref_or_block_separated
- * parsers.loop_body_pair.block^0
- + (V("Paragraph") + V("Plain"))
- * parsers.loop_body_pair.par^0)
- * parsers.content_blank^0
-
- parsers.indented_content = function()
- return Ct( (V("Reference") + (parsers.blankline / ""))
- * parsers.content_blank^0
- * parsers.check_minimal_indent
- * parsers.content_loop
- + (V("Reference") + (parsers.blankline / ""))
- * parsers.content_blank^0
- + parsers.content_loop)
- end
-
- parsers.add_indent = function(pattern, name, breakable)
- return Cg(Cmt( Cb("indent_info")
- * Ct(pattern)
- * (#parsers.linechar * Cc(false) + Cc(true)) -- check if starter is blank
- * Cc(name)
- * Cc(breakable),
- process_starter_indent), "indent_info")
- end
-
- if options.hashEnumerators then
- parsers.dig = parsers.digit + parsers.hash
- else
- parsers.dig = parsers.digit
- end
-
- parsers.enumerator = function(delimiter_type, interrupting)
- local delimiter_range
- local allowed_end
- if interrupting then
- delimiter_range = P("1")
- allowed_end = C(parsers.spacechar^1) * #parsers.linechar
- else
- delimiter_range = parsers.dig * parsers.dig^-8
- allowed_end = C(parsers.spacechar^1) + #(parsers.newline + parsers.eof)
- end
-
- return parsers.check_trail
- * Ct(C(delimiter_range) * C(delimiter_type))
- * allowed_end
- end
-
- parsers.starter = parsers.bullet(parsers.dash)
- + parsers.bullet(parsers.asterisk)
- + parsers.bullet(parsers.plus)
- + parsers.enumerator(parsers.period)
- + parsers.enumerator(parsers.rparent)
-
- parsers.blockquote_start = parsers.check_trail * C(parsers.more) * C(parsers.spacechar^0)
-
- parsers.blockquote_body = parsers.add_indent(parsers.blockquote_start, "bq", true)
- * parsers.indented_content()
- * remove_indent("bq")
-
- if not options.breakableBlockquotes then
- parsers.blockquote_body = parsers.add_indent(parsers.blockquote_start, "bq", false)
- * parsers.indented_content()
- * remove_indent("bq")
- end
- local function parse_content_part(content_part)
- local rope = util.rope_to_string(content_part)
- local parsed = self.parser_functions.parse_inlines_no_link_or_emphasis(rope)
- parsed.indent_info = nil
- return parsed
- end
-
- local function collect_emphasis_content(t, opening_index, closing_index)
- local content = {}
-
- local content_part = {}
- for i = opening_index, closing_index do
- local value = t[i]
-
- if value.rendered ~= nil then
- content[#content + 1] = parse_content_part(content_part)
- content_part = {}
- content[#content + 1] = value.rendered
- value.rendered = nil
- else
- if value.type == "delimiter" and value.element == "emphasis" then
- if value.is_active then
- content_part[#content_part + 1] = string.rep(value.character, value.current_count)
- end
- else
- content_part[#content_part + 1] = value.content
- end
- value.content = ''
- value.is_active = false
- end
- end
-
- if next(content_part) ~= nil then
- content[#content + 1] = parse_content_part(content_part)
- end
-
- return content
- end
-
- local function fill_emph(t, opening_index, closing_index)
- local content = collect_emphasis_content(t, opening_index + 1, closing_index - 1)
- t[opening_index + 1].is_active = true
- t[opening_index + 1].rendered = writer.emphasis(content)
- end
-
- local function fill_strong(t, opening_index, closing_index)
- local content = collect_emphasis_content(t, opening_index + 1, closing_index - 1)
- t[opening_index + 1].is_active = true
- t[opening_index + 1].rendered = writer.strong(content)
- end
-
- local function breaks_three_rule(opening_delimiter, closing_delimiter)
- return (opening_delimiter.is_closing or closing_delimiter.is_opening) and
- ((opening_delimiter.original_count + closing_delimiter.original_count) % 3 == 0) and
- (opening_delimiter.original_count % 3 ~= 0 or closing_delimiter.original_count % 3 ~= 0)
- end
-
- local function find_emphasis_opener(t, bottom_index, latest_index, character, closing_delimiter)
- for i = latest_index, bottom_index, -1 do
- local value = t[i]
- if value.is_active and
- value.is_opening and
- value.type == "delimiter" and
- value.element == "emphasis" and
- (value.character == character) and
- (value.current_count > 0) then
- if not breaks_three_rule(value, closing_delimiter) then
- return i
- end
- end
- end
- end
-
- local function process_emphasis(t, opening_index, closing_index)
- for i = opening_index, closing_index do
- local value = t[i]
- if value.type == "delimiter" and value.element == "emphasis" then
- local delimiter_length = string.len(value.content)
- value.character = string.sub(value.content, 1, 1)
- value.current_count = delimiter_length
- value.original_count = delimiter_length
- end
- end
-
- local openers_bottom = {
- ['*'] = {
- [true] = {opening_index, opening_index, opening_index},
- [false] = {opening_index, opening_index, opening_index}
- },
- ['_'] = {
- [true] = {opening_index, opening_index, opening_index},
- [false] = {opening_index, opening_index, opening_index}
- }
- }
-
- local current_position = opening_index
- local max_position = closing_index
-
- while current_position <= max_position do
- local value = t[current_position]
-
- if value.type ~= "delimiter" or
- value.element ~= "emphasis" or
- not value.is_active or
- not value.is_closing or
- (value.current_count <= 0) then
- current_position = current_position + 1
- goto continue
- end
-
- local character = value.character
- local is_opening = value.is_opening
- local closing_length_modulo_three = value.original_count % 3
-
- local current_openers_bottom = openers_bottom[character][is_opening][closing_length_modulo_three + 1]
-
- local opener_position = find_emphasis_opener(t, current_openers_bottom, current_position - 1, character, value)
-
- if (opener_position == nil) then
- openers_bottom[character][is_opening][closing_length_modulo_three + 1] = current_position
- current_position = current_position + 1
- goto continue
- end
-
- local opening_delimiter = t[opener_position]
-
- local current_opening_count = opening_delimiter.current_count
- local current_closing_count = t[current_position].current_count
-
- if (current_opening_count >= 2) and (current_closing_count >= 2) then
- opening_delimiter.current_count = current_opening_count - 2
- t[current_position].current_count = current_closing_count - 2
- fill_strong(t, opener_position, current_position)
- else
- opening_delimiter.current_count = current_opening_count - 1
- t[current_position].current_count = current_closing_count - 1
- fill_emph(t, opener_position, current_position)
- end
-
- ::continue::
- end
- end
-
- local cont = lpeg.R("\128\191") -- continuation byte
-
- local function utf8_by_byte_count(n)
- if (n == 1) then
- return lpeg.R("\0\127")
- end
- if (n == 2) then
- return lpeg.R("\194\223") * cont
- end
- if (n == 3) then
- return lpeg.R("\224\239") * cont * cont
- end
- if (n == 4) then
- return lpeg.R("\240\244") * cont * cont * cont
- end
- end
- local function check_unicode_type(s, i, start_pos, end_pos, chartype)
- local c
- local char_length
- for pos = start_pos, end_pos, 1 do
- if (start_pos < 0) then
- char_length = -pos
- else
- char_length = pos + 1
- end
-
- if (chartype == "punctuation") then
- if lpeg.match(parsers.punctuation[char_length], s, i+pos) then
- return i
- end
- else
- c = lpeg.match({ C(utf8_by_byte_count(char_length)) },s,i+pos)
- if (c ~= nil) and (unicode.utf8.match(c, chartype)) then
- return i
- end
- end
- end
- end
-
- local function check_preceding_unicode_punctuation(s, i)
- return check_unicode_type(s, i, -4, -1, "punctuation")
- end
-
- local function check_preceding_unicode_whitespace(s, i)
- return check_unicode_type(s, i, -4, -1, "%s")
- end
-
- local function check_following_unicode_punctuation(s, i)
- return check_unicode_type(s, i, 0, 3, "punctuation")
- end
-
- local function check_following_unicode_whitespace(s, i)
- return check_unicode_type(s, i, 0, 3, "%s")
- end
-
- parsers.unicode_preceding_punctuation = B(parsers.escapable)
- + Cmt(parsers.succeed, check_preceding_unicode_punctuation)
-
- parsers.unicode_preceding_whitespace = Cmt(parsers.succeed, check_preceding_unicode_whitespace)
-
- parsers.unicode_following_punctuation = #parsers.escapable
- + Cmt(parsers.succeed, check_following_unicode_punctuation)
-
- parsers.unicode_following_whitespace = Cmt(parsers.succeed, check_following_unicode_whitespace)
-
- parsers.delimiter_run = function(character)
- return (B(parsers.backslash * character) + -B(character))
- * character^1
- * -#character
- end
-
- parsers.left_flanking_delimiter_run = function(character)
- return (B( parsers.any)
- * (parsers.unicode_preceding_punctuation + parsers.unicode_preceding_whitespace)
- + -B(parsers.any))
- * parsers.delimiter_run(character)
- * parsers.unicode_following_punctuation
- + parsers.delimiter_run(character)
- * -#(parsers.unicode_following_punctuation + parsers.unicode_following_whitespace
- + parsers.eof)
- end
-
- parsers.right_flanking_delimiter_run = function(character)
- return parsers.unicode_preceding_punctuation
- * parsers.delimiter_run(character)
- * (parsers.unicode_following_punctuation + parsers.unicode_following_whitespace
- + parsers.eof)
- + (B(parsers.any)
- * -(parsers.unicode_preceding_punctuation + parsers.unicode_preceding_whitespace))
- * parsers.delimiter_run(character)
- end
-
- if options.underscores then
- parsers.emph_start = parsers.left_flanking_delimiter_run(parsers.asterisk)
- + (-#parsers.right_flanking_delimiter_run(parsers.underscore)
- + (parsers.unicode_preceding_punctuation
- * #parsers.right_flanking_delimiter_run(parsers.underscore)))
- * parsers.left_flanking_delimiter_run(parsers.underscore)
-
- parsers.emph_end = parsers.right_flanking_delimiter_run(parsers.asterisk)
- + (-#parsers.left_flanking_delimiter_run(parsers.underscore)
- + #(parsers.left_flanking_delimiter_run(parsers.underscore)
- * parsers.unicode_following_punctuation))
- * parsers.right_flanking_delimiter_run(parsers.underscore)
- else
- parsers.emph_start = parsers.left_flanking_delimiter_run(parsers.asterisk)
-
- parsers.emph_end = parsers.right_flanking_delimiter_run(parsers.asterisk)
- end
-
- parsers.emph_capturing_open_and_close = #parsers.emph_start * #parsers.emph_end
- * Ct( Cg(Cc("delimiter"), "type")
- * Cg(Cc("emphasis"), "element")
- * Cg(C(parsers.emph_start), "content")
- * Cg(Cc(true), "is_opening")
- * Cg(Cc(true), "is_closing"))
-
- parsers.emph_capturing_open = Ct( Cg(Cc("delimiter"), "type")
- * Cg(Cc("emphasis"), "element")
- * Cg(C(parsers.emph_start), "content")
- * Cg(Cc(true), "is_opening")
- * Cg(Cc(false), "is_closing"))
-
- parsers.emph_capturing_close = Ct( Cg(Cc("delimiter"), "type")
- * Cg(Cc("emphasis"), "element")
- * Cg(C(parsers.emph_end), "content")
- * Cg(Cc(false), "is_opening")
- * Cg(Cc(true), "is_closing"))
-
- parsers.emph_open_or_close = parsers.emph_capturing_open_and_close
- + parsers.emph_capturing_open
- + parsers.emph_capturing_close
-
- parsers.emph_open = parsers.emph_capturing_open_and_close
- + parsers.emph_capturing_open
-
- parsers.emph_close = parsers.emph_capturing_open_and_close
- + parsers.emph_capturing_close
-
- -- List of references defined in the document
- local references
-
- function self.register_link(_, tag, url, title,
- attributes)
- local normalized_tag = self.normalize_tag(tag)
- if references[normalized_tag] == nil then
- references[normalized_tag] = {
- url = url,
- title = title,
- attributes = attributes
- }
- end
- return ""
- end
-
- function self.lookup_reference(tag)
- return references[self.normalize_tag(tag)]
- end
-
- parsers.title_s_direct_ref = parsers.squote
- * Cs((parsers.html_entities
- + (parsers.anyescaped - parsers.squote - parsers.blankline^2))^0)
- * parsers.squote
-
- parsers.title_d_direct_ref = parsers.dquote
- * Cs((parsers.html_entities
- + (parsers.anyescaped - parsers.dquote - parsers.blankline^2))^0)
- * parsers.dquote
-
- parsers.title_p_direct_ref = parsers.lparent
- * Cs((parsers.html_entities
- + (parsers.anyescaped - parsers.lparent - parsers.rparent - parsers.blankline^2))^0)
- * parsers.rparent
-
- parsers.title_direct_ref = parsers.title_s_direct_ref
- + parsers.title_d_direct_ref
- + parsers.title_p_direct_ref
-
- parsers.inline_direct_ref_inside = parsers.lparent * parsers.spnl
- * Cg(parsers.url + Cc(""), "url")
- * parsers.spnl
- * Cg(parsers.title_direct_ref + Cc(""), "title")
- * parsers.spnl * parsers.rparent
-
- parsers.inline_direct_ref = parsers.lparent * parsers.spnlc
- * Cg(parsers.url + Cc(""), "url")
- * parsers.spnlc
- * Cg(parsers.title + Cc(""), "title")
- * parsers.spnlc * parsers.rparent
-
- parsers.empty_link = parsers.lbracket
- * parsers.rbracket
-
- parsers.inline_link = parsers.link_text
- * parsers.inline_direct_ref
-
- parsers.full_link = parsers.link_text
- * parsers.link_label
-
- parsers.shortcut_link = parsers.link_label
- * -(parsers.empty_link + parsers.link_label)
-
- parsers.collapsed_link = parsers.link_label
- * parsers.empty_link
-
- parsers.image_opening = #(parsers.exclamation * parsers.inline_link)
- * Cg(Cc("inline"), "link_type")
- + #(parsers.exclamation * parsers.full_link)
- * Cg(Cc("full"), "link_type")
- + #(parsers.exclamation * parsers.collapsed_link)
- * Cg(Cc("collapsed"), "link_type")
- + #(parsers.exclamation * parsers.shortcut_link)
- * Cg(Cc("shortcut"), "link_type")
- + #(parsers.exclamation * parsers.empty_link)
- * Cg(Cc("empty"), "link_type")
-
- parsers.link_opening = #parsers.inline_link
- * Cg(Cc("inline"), "link_type")
- + #parsers.full_link
- * Cg(Cc("full"), "link_type")
- + #parsers.collapsed_link
- * Cg(Cc("collapsed"), "link_type")
- + #parsers.shortcut_link
- * Cg(Cc("shortcut"), "link_type")
- + #parsers.empty_link
- * Cg(Cc("empty_link"), "link_type")
- + #parsers.link_text
- * Cg(Cc("link_text"), "link_type")
-
- parsers.link_image_opening = Ct( Cg(Cc("delimiter"), "type")
- * Cg(Cc(true), "is_opening")
- * Cg(Cc(false), "is_closing")
- * ( Cg(Cc("image"), "element")
- * parsers.image_opening
- * Cg(parsers.exclamation * parsers.lbracket, "content")
- + Cg(Cc("link"), "element")
- * parsers.link_opening
- * Cg(parsers.lbracket, "content")))
-
- parsers.link_image_closing = Ct( Cg(Cc("delimiter"), "type")
- * Cg(Cc("link"), "element")
- * Cg(Cc(false), "is_opening")
- * Cg(Cc(true), "is_closing")
- * ( Cg(Cc(true), "is_direct")
- * Cg(parsers.rbracket * #parsers.inline_direct_ref, "content")
- + Cg(Cc(false), "is_direct")
- * Cg(parsers.rbracket, "content")))
-
- parsers.link_image_open_or_close = parsers.link_image_opening
- + parsers.link_image_closing
-
- if options.html then
- parsers.link_emph_precedence = parsers.inticks
- + parsers.autolink
- + parsers.html_inline_tags
- else
- parsers.link_emph_precedence = parsers.inticks
- + parsers.autolink
- end
-
- parsers.link_and_emph_endline = parsers.newline
- * ((parsers.check_minimal_indent
- * -V("EndlineExceptions")
- + parsers.check_optional_indent
- * -V("EndlineExceptions")
- * -parsers.starter) / "")
- * parsers.spacechar^0 / "\n"
-
- parsers.link_and_emph_content = Ct( Cg(Cc("content"), "type")
- * Cg(Cs(( parsers.link_emph_precedence
- + parsers.backslash * parsers.any
- + parsers.link_and_emph_endline
- + (parsers.linechar
- - parsers.blankline^2
- - parsers.link_image_open_or_close
- - parsers.emph_open_or_close))^0), "content"))
-
- parsers.link_and_emph_table = (parsers.link_image_opening + parsers.emph_open)
- * parsers.link_and_emph_content
- * ((parsers.link_image_open_or_close + parsers.emph_open_or_close)
- * parsers.link_and_emph_content)^1
-
- local function collect_link_content(t, opening_index, closing_index)
- local content = {}
- for i = opening_index, closing_index do
- content[#content + 1] = t[i].content
- end
- return util.rope_to_string(content)
- end
-
- local function find_link_opener(t, bottom_index, latest_index)
- for i = latest_index, bottom_index, -1 do
- local value = t[i]
- if value.type == "delimiter" and
- value.is_opening and
- (value.element == "link" or value.element == "image")
- and not value.removed then
- if value.is_active then
- return i
- end
- value.removed = true
- return nil
- end
- end
- end
-
- local function find_next_link_closing_index(t, latest_index)
- for i = latest_index, #t do
- local value = t[i]
- if value.is_closing and
- value.element == "link" and
- not value.removed then
- return i
- end
- end
- end
-
- local function disable_previous_link_openers(t, opening_index)
- if t[opening_index].element == "image" then
- return
- end
-
- for i = opening_index, 1, -1 do
- local value = t[i]
- if value.is_active and
- value.type == "delimiter" and
- value.is_opening and
- value.element == "link" then
- value.is_active = false
- end
- end
- end
-
- local function disable_range(t, opening_index, closing_index)
- for i = opening_index, closing_index do
- local value = t[i]
- if value.is_active then
- value.is_active = false
- if value.type == "delimiter" then
- value.removed = true
- end
- end
- end
- end
-
- local function delete_parsed_content_in_range(t, opening_index, closing_index)
- for i = opening_index, closing_index do
- t[i].rendered = nil
- end
- end
-
- local function empty_content_in_range(t, opening_index, closing_index)
- for i = opening_index, closing_index do
- t[i].content = ''
- end
- end
-
- local function join_attributes(reference_attributes, own_attributes)
- local merged_attributes = {}
- for _, attribute in ipairs(reference_attributes or {}) do
- table.insert(merged_attributes, attribute)
- end
- for _, attribute in ipairs(own_attributes or {}) do
- table.insert(merged_attributes, attribute)
- end
- if next(merged_attributes) == nil then
- merged_attributes = nil
- end
- return merged_attributes
- end
-
- local function render_link_or_image(t, opening_index, closing_index, content_end_index, reference)
- process_emphasis(t, opening_index, content_end_index)
- local mapped = collect_emphasis_content(t, opening_index + 1, content_end_index - 1)
-
- local rendered = {}
- if (t[opening_index].element == "link") then
- rendered = writer.link(mapped, reference.url, reference.title, reference.attributes)
- end
-
- if (t[opening_index].element == "image") then
- rendered = writer.image(mapped, reference.url, reference.title, reference.attributes)
- end
-
- t[opening_index].rendered = rendered
- delete_parsed_content_in_range(t, opening_index + 1, closing_index)
- empty_content_in_range(t, opening_index, closing_index)
- disable_previous_link_openers(t, opening_index)
- disable_range(t, opening_index, closing_index)
- end
-
- local function resolve_inline_following_content(t, closing_index, match_reference, match_link_attributes)
- local content = ""
- for i = closing_index + 1, #t do
- content = content .. t[i].content
- end
-
- local matching_content = parsers.succeed
-
- if match_reference then
- matching_content = matching_content * parsers.inline_direct_ref_inside
- end
-
- if match_link_attributes then
- matching_content = matching_content * Cg(Ct(parsers.attributes^-1), "attributes")
- end
-
- local matched = lpeg.match(Ct(matching_content * Cg(Cp(), "end_position")), content)
-
- local matched_count = matched.end_position - 1
- for i = closing_index + 1, #t do
- local value = t[i]
-
- local chars_left = matched_count
- matched_count = matched_count - #value.content
-
- if matched_count <= 0 then
- value.content = value.content:sub(chars_left + 1)
- break
- end
-
- value.content = ''
- value.is_active = false
- end
-
- local attributes = matched.attributes
- if attributes == nil or next(attributes) == nil then
- attributes = nil
- end
-
- return {
- url = matched.url or "",
- title = matched.title or "",
- attributes = attributes
- }
- end
-
- local function resolve_inline_link(t, opening_index, closing_index)
- local inline_content = resolve_inline_following_content(t, closing_index, true, t.match_link_attributes)
- render_link_or_image(t, opening_index, closing_index, closing_index, inline_content)
- end
-
- local function resolve_shortcut_link(t, opening_index, closing_index)
- local content = collect_link_content(t, opening_index + 1, closing_index - 1)
- local r = self.lookup_reference(content)
-
- if r then
- local inline_content = resolve_inline_following_content(t, closing_index, false, t.match_link_attributes)
- r.attributes = join_attributes(r.attributes, inline_content.attributes)
- render_link_or_image(t, opening_index, closing_index, closing_index, r)
- end
- end
-
- local function resolve_full_link(t, opening_index, closing_index)
- local next_link_closing_index = find_next_link_closing_index(t, closing_index + 4)
- local next_link_content = collect_link_content(t, closing_index + 3, next_link_closing_index - 1)
- local r = self.lookup_reference(next_link_content)
-
- if r then
- local inline_content = resolve_inline_following_content(t, next_link_closing_index, false,
- t.match_link_attributes)
- r.attributes = join_attributes(r.attributes, inline_content.attributes)
- render_link_or_image(t, opening_index, next_link_closing_index, closing_index, r)
- end
- end
-
- local function resolve_collapsed_link(t, opening_index, closing_index)
- local next_link_closing_index = find_next_link_closing_index(t, closing_index + 4)
- local content = collect_link_content(t, opening_index + 1, closing_index - 1)
- local r = self.lookup_reference(content)
-
- if r then
- local inline_content = resolve_inline_following_content(t, closing_index, false, t.match_link_attributes)
- r.attributes = join_attributes(r.attributes, inline_content.attributes)
- render_link_or_image(t, opening_index, next_link_closing_index, closing_index, r)
- end
- end
-
- local function process_links_and_emphasis(t)
- for _,value in ipairs(t) do
- value.is_active = true
- end
-
- for i,value in ipairs(t) do
- if not value.is_closing or
- value.type ~= "delimiter" or
- not (value.element == "link" or value.element == "image") then
- goto continue
- end
-
- local opener_position = find_link_opener(t, 1, i - 1)
- if (opener_position == nil) then
- goto continue
- end
-
- local opening_delimiter = t[opener_position]
- opening_delimiter.removed = true
-
- local link_type = opening_delimiter.link_type
-
- if (link_type == "inline") then
- resolve_inline_link(t, opener_position, i)
- end
- if (link_type == "shortcut") then
- resolve_shortcut_link(t, opener_position, i)
- end
- if (link_type == "full") then
- resolve_full_link(t, opener_position, i)
- end
- if (link_type == "collapsed") then
- resolve_collapsed_link(t, opener_position, i)
- end
-
- ::continue::
- end
-
- t[#t].content = t[#t].content:gsub("%s*$","")
-
- process_emphasis(t, 1, #t)
- local final_result = collect_emphasis_content(t, 1, #t)
- return final_result
- end
-
- function self.defer_link_and_emphasis_processing(delimiter_table)
- return writer.defer_call(function()
- return process_links_and_emphasis(delimiter_table)
- end)
- end
-
- parsers.Str = (parsers.normalchar * (parsers.normalchar + parsers.at)^0)
- / writer.string
-
- parsers.Symbol = (parsers.backtick^1 + V("SpecialChar"))
- / writer.string
-
- parsers.Ellipsis = P("...") / writer.ellipsis
-
- parsers.Smart = parsers.Ellipsis
-
- parsers.Code = parsers.inticks / writer.code
-
- if options.blankBeforeBlockquote then
- parsers.bqstart = parsers.fail
- else
- parsers.bqstart = parsers.blockquote_start
- end
-
- if options.blankBeforeHeading then
- parsers.headerstart = parsers.fail
- else
- parsers.headerstart = parsers.atx_heading
- end
-
- if options.blankBeforeList then
- parsers.interrupting_bullets = parsers.fail
- parsers.interrupting_enumerators = parsers.fail
- else
- parsers.interrupting_bullets = parsers.bullet(parsers.dash, true)
- + parsers.bullet(parsers.asterisk, true)
- + parsers.bullet(parsers.plus, true)
-
- parsers.interrupting_enumerators = parsers.enumerator(parsers.period, true)
- + parsers.enumerator(parsers.rparent, true)
- end
-
- if options.html then
- parsers.html_interrupting = parsers.check_trail
- * ( parsers.html_incomplete_open_tag
- + parsers.html_incomplete_close_tag
- + parsers.html_incomplete_open_special_tag
- + parsers.html_comment_start
- + parsers.html_cdatasection_start
- + parsers.html_declaration_start
- + parsers.html_instruction_start
- - parsers.html_close_special_tag
- - parsers.html_empty_special_tag)
- else
- parsers.html_interrupting = parsers.fail
- end
-
- parsers.EndlineExceptions
- = parsers.blankline -- paragraph break
- + parsers.eof -- end of document
- + parsers.bqstart
- + parsers.thematic_break_lines
- + parsers.interrupting_bullets
- + parsers.interrupting_enumerators
- + parsers.headerstart
- + parsers.html_interrupting
-
- parsers.NoSoftLineBreakEndlineExceptions = parsers.EndlineExceptions
-
- parsers.endline = parsers.newline
- * (parsers.check_minimal_indent
- * -V("EndlineExceptions")
- + parsers.check_optional_indent
- * -V("EndlineExceptions")
- * -parsers.starter)
- * parsers.spacechar^0
-
- parsers.Endline = parsers.endline
- / writer.soft_line_break
-
- parsers.EndlineNoSub = parsers.endline
-
- parsers.NoSoftLineBreakEndline
- = parsers.newline
- * (parsers.check_minimal_indent
- * -V("NoSoftLineBreakEndlineExceptions")
- + parsers.check_optional_indent
- * -V("NoSoftLineBreakEndlineExceptions")
- * -parsers.starter)
- * parsers.spacechar^0
- / writer.space
-
- parsers.EndlineBreak = parsers.backslash * parsers.Endline
- / writer.hard_line_break
-
- parsers.OptionalIndent
- = parsers.spacechar^1 / writer.space
-
- parsers.Space = parsers.spacechar^2 * parsers.Endline
- / writer.hard_line_break
- + parsers.spacechar^1 * parsers.Endline^-1 * parsers.eof / self.expandtabs
- + parsers.spacechar^1 * parsers.Endline
- / writer.soft_line_break
- + parsers.spacechar^1 * -parsers.newline / self.expandtabs
-
- parsers.NoSoftLineBreakSpace
- = parsers.spacechar^2 * parsers.Endline
- / writer.hard_line_break
- + parsers.spacechar^1 * parsers.Endline^-1 * parsers.eof / self.expandtabs
- + parsers.spacechar^1 * parsers.Endline
- / writer.soft_line_break
- + parsers.spacechar^1 * -parsers.newline / self.expandtabs
-
- parsers.NonbreakingEndline
- = parsers.endline
- / writer.soft_line_break
-
- parsers.NonbreakingSpace
- = parsers.spacechar^2 * parsers.Endline
- / writer.hard_line_break
- + parsers.spacechar^1 * parsers.Endline^-1 * parsers.eof / ""
- + parsers.spacechar^1 * parsers.Endline
- * parsers.optionalspace
- / writer.soft_line_break
- + parsers.spacechar^1 * parsers.optionalspace
- / writer.nbsp
-
-function self.auto_link_url(url, attributes)
- return writer.link(writer.escape(url),
- url, nil, attributes)
-end
-function self.auto_link_email(email, attributes)
- return writer.link(writer.escape(email),
- "mailto:"..email,
- nil, attributes)
-end
-
- parsers.AutoLinkUrl = parsers.auto_link_url
- / self.auto_link_url
-
- parsers.AutoLinkEmail
- = parsers.auto_link_email
- / self.auto_link_email
-
- parsers.AutoLinkRelativeReference
- = parsers.auto_link_relative_reference
- / self.auto_link_url
-
- parsers.LinkAndEmph = Ct(parsers.link_and_emph_table)
- / self.defer_link_and_emphasis_processing
-
- parsers.EscapedChar = parsers.backslash * C(parsers.escapable) / writer.string
-
- parsers.InlineHtml = Cs(parsers.html_inline_comment) / writer.inline_html_comment
- + Cs(parsers.html_any_empty_inline_tag
- + parsers.html_inline_instruction
- + parsers.html_inline_cdatasection
- + parsers.html_inline_declaration
- + parsers.html_any_open_inline_tag
- + parsers.html_any_close_tag)
- / writer.inline_html_tag
-
- parsers.HtmlEntity = parsers.html_entities / writer.string
- parsers.DisplayHtml = Cs(parsers.check_trail
- * ( parsers.html_comment
- + parsers.html_special_block
- + parsers.html_block
- + parsers.html_any_block
- + parsers.html_instruction
- + parsers.html_cdatasection
- + parsers.html_declaration))
- / writer.block_html_element
-
- parsers.indented_non_blank_line = parsers.indentedline - parsers.blankline
-
- parsers.Verbatim = Cs(
- parsers.check_code_trail
- * (parsers.line - parsers.blankline)
- * ((parsers.check_minimal_blank_indent_and_full_code_trail * parsers.blankline)^0
- * ((parsers.check_minimal_indent / "") * parsers.check_code_trail
- * (parsers.line - parsers.blankline))^1)^0
- ) / self.expandtabs / writer.verbatim
-
- parsers.Blockquote = parsers.blockquote_body
- / writer.blockquote
-
- parsers.ThematicBreak = parsers.thematic_break_lines
- / writer.thematic_break
-
- parsers.Reference = parsers.define_reference_parser
- / self.register_link
-
- parsers.Paragraph = parsers.freeze_trail
- * (Ct((parsers.Inline)^1)
- * (parsers.newline + parsers.eof)
- * parsers.unfreeze_trail
- / writer.paragraph)
-
- parsers.Plain = parsers.nonindentspace * Ct(parsers.Inline^1)
- / writer.plain
-
- if options.taskLists then
- parsers.tickbox = ( parsers.ticked_box
- + parsers.halfticked_box
- + parsers.unticked_box
- ) / writer.tickbox
- else
- parsers.tickbox = parsers.fail
- end
-
- parsers.list_blank = parsers.conditionally_indented_blankline
-
- parsers.ref_or_block_list_separated = parsers.sep_group_no_output(parsers.list_blank)
- * parsers.minimally_indented_ref
- + parsers.block_sep_group(parsers.list_blank)
- * parsers.minimally_indented_block
-
- parsers.ref_or_block_non_separated = parsers.minimally_indented_ref
- + (parsers.succeed / writer.interblocksep)
- * parsers.minimally_indented_block
- - parsers.minimally_indented_blankline
-
- parsers.tight_list_loop_body_pair =
- parsers.create_loop_body_pair(parsers.ref_or_block_non_separated,
- parsers.minimally_indented_par_or_plain_no_blank,
- (parsers.succeed / writer.interblocksep),
- (parsers.succeed / writer.paragraphsep))
-
- parsers.loose_list_loop_body_pair =
- parsers.create_loop_body_pair(parsers.ref_or_block_list_separated,
- parsers.minimally_indented_par_or_plain,
- parsers.block_sep_group(parsers.list_blank),
- parsers.par_sep_group(parsers.list_blank))
-
- parsers.tight_list_content_loop = V("Block")
- * parsers.tight_list_loop_body_pair.block^0
- + (V("Paragraph") + V("Plain"))
- * parsers.ref_or_block_non_separated
- * parsers.tight_list_loop_body_pair.block^0
- + (V("Paragraph") + V("Plain"))
- * parsers.tight_list_loop_body_pair.par^0
-
- parsers.loose_list_content_loop = V("Block")
- * parsers.loose_list_loop_body_pair.block^0
- + (V("Paragraph") + V("Plain"))
- * parsers.ref_or_block_list_separated
- * parsers.loose_list_loop_body_pair.block^0
- + (V("Paragraph") + V("Plain"))
- * parsers.loose_list_loop_body_pair.par^0
-
- parsers.list_item_tightness_condition = -#( parsers.list_blank^0
- * parsers.minimally_indented_ref_or_block_or_par)
- * remove_indent("li")
- + remove_indent("li")
- * parsers.fail
-
- parsers.indented_content_tight = Ct( (parsers.blankline / "")
- * #parsers.list_blank
- * remove_indent("li")
- + ( (V("Reference") + (parsers.blankline / ""))
- * parsers.check_minimal_indent
- * parsers.tight_list_content_loop
- + (V("Reference") + (parsers.blankline / ""))
- + (parsers.tickbox^-1 / writer.escape)
- * parsers.tight_list_content_loop
- )
- * parsers.list_item_tightness_condition
- )
-
- parsers.indented_content_loose = Ct( (parsers.blankline / "")
- * #parsers.list_blank
- + ( (V("Reference") + (parsers.blankline / ""))
- * parsers.check_minimal_indent
- * parsers.loose_list_content_loop
- + (V("Reference") + (parsers.blankline / ""))
- + (parsers.tickbox^-1 / writer.escape)
- * parsers.loose_list_content_loop
- )
- )
-
- parsers.TightListItem = function(starter)
- return -parsers.ThematicBreak
- * parsers.add_indent(starter, "li")
- * parsers.indented_content_tight
- end
-
- parsers.LooseListItem = function(starter)
- return -parsers.ThematicBreak
- * parsers.add_indent(starter, "li")
- * parsers.indented_content_loose
- * remove_indent("li")
- end
-
- parsers.BulletListOfType = function(bullet_type)
- local bullet = parsers.bullet(bullet_type)
- return ( Ct( parsers.TightListItem(bullet)
- * ( (parsers.check_minimal_indent / "")
- * parsers.TightListItem(bullet)
- )^0
- )
- * Cc(true)
- * -#( (parsers.list_blank^0 / "")
- * parsers.check_minimal_indent
- * (bullet - parsers.ThematicBreak)
- )
- + Ct( parsers.LooseListItem(bullet)
- * ( (parsers.list_blank^0 / "")
- * (parsers.check_minimal_indent / "")
- * parsers.LooseListItem(bullet)
- )^0
- )
- * Cc(false)
- ) / writer.bulletlist
- end
-
- parsers.BulletList = parsers.BulletListOfType(parsers.dash)
- + parsers.BulletListOfType(parsers.asterisk)
- + parsers.BulletListOfType(parsers.plus)
-
- local function ordered_list(items,tight,starter)
- local startnum = starter[2][1]
- if options.startNumber then
- startnum = tonumber(startnum) or 1 -- fallback for '#'
- if startnum ~= nil then
- startnum = math.floor(startnum)
- end
- else
- startnum = nil
- end
- return writer.orderedlist(items,tight,startnum)
- end
-
- parsers.OrderedListOfType = function(delimiter_type)
- local enumerator = parsers.enumerator(delimiter_type)
- return Cg(enumerator, "listtype")
- * (Ct( parsers.TightListItem(Cb("listtype"))
- * ((parsers.check_minimal_indent / "") * parsers.TightListItem(enumerator))^0)
- * Cc(true)
- * -#((parsers.list_blank^0 / "")
- * parsers.check_minimal_indent * enumerator)
- + Ct( parsers.LooseListItem(Cb("listtype"))
- * ((parsers.list_blank^0 / "")
- * (parsers.check_minimal_indent / "") * parsers.LooseListItem(enumerator))^0)
- * Cc(false)
- ) * Ct(Cb("listtype")) / ordered_list
- end
-
- parsers.OrderedList = parsers.OrderedListOfType(parsers.period)
- + parsers.OrderedListOfType(parsers.rparent)
- parsers.Blank = parsers.blankline / ""
- + V("Reference")
- function parsers.parse_heading_text(s)
- local inlines = self.parser_functions.parse_inlines(s)
- local flatten_inlines = self.writer.flatten_inlines
- self.writer.flatten_inlines = true
- local flat_text = self.parser_functions.parse_inlines(s)
- flat_text = util.rope_to_string(flat_text)
- self.writer.flatten_inlines = flatten_inlines
- return {flat_text, inlines}
- end
-
- -- parse atx header
- parsers.AtxHeading = parsers.check_trail_no_rem
- * Cg(parsers.heading_start, "level")
- * ((C( parsers.optionalspace
- * parsers.hash^0
- * parsers.optionalspace
- * parsers.newline)
- + parsers.spacechar^1
- * C(parsers.line))
- / strip_atx_end
- / parsers.parse_heading_text)
- * Cb("level")
- / writer.heading
-
- parsers.heading_line = parsers.linechar^1
- - parsers.thematic_break_lines
-
- parsers.heading_text = parsers.heading_line
- * ((V("Endline") / "\n") * (parsers.heading_line - parsers.heading_level))^0
- * parsers.newline^-1
-
- parsers.SetextHeading = parsers.freeze_trail * parsers.check_trail_no_rem
- * #(parsers.heading_text
- * parsers.check_minimal_indent * parsers.check_trail * parsers.heading_level)
- * Cs(parsers.heading_text)
- / parsers.parse_heading_text
- * parsers.check_minimal_indent_and_trail * parsers.heading_level
- * parsers.newline
- * parsers.unfreeze_trail
- / writer.heading
-
- parsers.Heading = parsers.AtxHeading + parsers.SetextHeading
- function self.finalize_grammar(extensions)
- local walkable_syntax = (function(global_walkable_syntax)
- local local_walkable_syntax = {}
- for lhs, rule in pairs(global_walkable_syntax) do
- local_walkable_syntax[lhs] = util.table_copy(rule)
- end
- return local_walkable_syntax
- end)(walkable_syntax)
- local current_extension_name = nil
- self.insert_pattern = function(selector, pattern, pattern_name)
- assert(pattern_name == nil or type(pattern_name) == "string")
- local _, _, lhs, pos, rhs = selector:find("^(%a+)%s+([%a%s]+%a+)%s+(%a+)$")
- assert(lhs ~= nil,
- [[Expected selector in form "LHS (before|after|instead of) RHS", not "]]
- .. selector .. [["]])
- assert(walkable_syntax[lhs] ~= nil,
- [[Rule ]] .. lhs .. [[ -> ... does not exist in markdown grammar]])
- assert(pos == "before" or pos == "after" or pos == "instead of",
- [[Expected positional specifier "before", "after", or "instead of", not "]]
- .. pos .. [["]])
- local rule = walkable_syntax[lhs]
- local index = nil
- for current_index, current_rhs in ipairs(rule) do
- if type(current_rhs) == "string" and current_rhs == rhs then
- index = current_index
- if pos == "after" then
- index = index + 1
- end
- break
- end
- end
- assert(index ~= nil,
- [[Rule ]] .. lhs .. [[ -> ]] .. rhs
- .. [[ does not exist in markdown grammar]])
- local accountable_pattern
- if current_extension_name then
- accountable_pattern = { pattern, current_extension_name, pattern_name }
- else
- assert(type(pattern) == "string",
- [[reader->insert_pattern() was called outside an extension with ]]
- .. [[a PEG pattern instead of a rule name]])
- accountable_pattern = pattern
- end
- if pos == "instead of" then
- rule[index] = accountable_pattern
- else
- table.insert(rule, index, accountable_pattern)
- end
- end
- local syntax =
- { "Blocks",
-
- Blocks = V("InitializeState")
- * ( V("ExpectedJekyllData")
- * (V("Blank")^0 / writer.interblocksep)
- )^-1
- * V("Blank")^0
- * ( V("Block")
- * ( V("Blank")^0 * parsers.eof
- + ( V("Blank")^2 / writer.paragraphsep
- + V("Blank")^0 / writer.interblocksep
- )
- )
- + ( V("Paragraph") + V("Plain") )
- * ( V("Blank")^0 * parsers.eof
- + ( V("Blank")^2 / writer.paragraphsep
- + V("Blank")^0 / writer.interblocksep
- )
- )
- * V("Block")
- * ( V("Blank")^0 * parsers.eof
- + ( V("Blank")^2 / writer.paragraphsep
- + V("Blank")^0 / writer.interblocksep
- )
- )
- + ( V("Paragraph") + V("Plain") )
- * ( V("Blank")^0 * parsers.eof
- + V("Blank")^0 / writer.paragraphsep
- )
- )^0,
-
- ExpectedJekyllData = parsers.fail,
-
- Blank = parsers.Blank,
- Reference = parsers.Reference,
-
- Blockquote = parsers.Blockquote,
- Verbatim = parsers.Verbatim,
- ThematicBreak = parsers.ThematicBreak,
- BulletList = parsers.BulletList,
- OrderedList = parsers.OrderedList,
- DisplayHtml = parsers.DisplayHtml,
- Heading = parsers.Heading,
- Paragraph = parsers.Paragraph,
- Plain = parsers.Plain,
-
- EndlineExceptions = parsers.EndlineExceptions,
- NoSoftLineBreakEndlineExceptions
- = parsers.NoSoftLineBreakEndlineExceptions,
-
- Str = parsers.Str,
- Space = parsers.Space,
- NoSoftLineBreakSpace = parsers.NoSoftLineBreakSpace,
- OptionalIndent = parsers.OptionalIndent,
- Endline = parsers.Endline,
- EndlineNoSub = parsers.EndlineNoSub,
- NoSoftLineBreakEndline
- = parsers.NoSoftLineBreakEndline,
- EndlineBreak = parsers.EndlineBreak,
- LinkAndEmph = parsers.LinkAndEmph,
- Code = parsers.Code,
- AutoLinkUrl = parsers.AutoLinkUrl,
- AutoLinkEmail = parsers.AutoLinkEmail,
- AutoLinkRelativeReference
- = parsers.AutoLinkRelativeReference,
- InlineHtml = parsers.InlineHtml,
- HtmlEntity = parsers.HtmlEntity,
- EscapedChar = parsers.EscapedChar,
- Smart = parsers.Smart,
- Symbol = parsers.Symbol,
- SpecialChar = parsers.fail,
- InitializeState = parsers.succeed,
- }
- self.update_rule = function(rule_name, get_pattern)
- assert(current_extension_name ~= nil)
- assert(syntax[rule_name] ~= nil,
- [[Rule ]] .. rule_name .. [[ -> ... does not exist in markdown grammar]])
- local previous_pattern
- local extension_name
- if walkable_syntax[rule_name] then
- local previous_accountable_pattern = walkable_syntax[rule_name][1]
- previous_pattern = previous_accountable_pattern[1]
- extension_name = previous_accountable_pattern[2] .. ", " .. current_extension_name
- else
- previous_pattern = nil
- extension_name = current_extension_name
- end
- local pattern
- if type(get_pattern) == "function" then
- pattern = get_pattern(previous_pattern)
- else
- assert(previous_pattern == nil,
- [[Rule ]] .. rule_name ..
- [[ has already been updated by ]] .. extension_name)
- pattern = get_pattern
- end
- local accountable_pattern = { pattern, extension_name, rule_name }
- walkable_syntax[rule_name] = { accountable_pattern }
- end
- local special_characters = {}
- self.add_special_character = function(c)
- table.insert(special_characters, c)
- syntax.SpecialChar = S(table.concat(special_characters, ""))
- end
-
- self.add_special_character("*")
- self.add_special_character("[")
- self.add_special_character("]")
- self.add_special_character("<")
- self.add_special_character("!")
- self.add_special_character("\\")
- self.initialize_named_group = function(name, value)
- local pattern = Ct("")
- if value ~= nil then
- pattern = pattern / value
- end
- syntax.InitializeState = syntax.InitializeState
- * Cg(pattern, name)
- end
- self.initialize_named_group("indent_info")
- for _, extension in ipairs(extensions) do
- current_extension_name = extension.name
- extension.extend_writer(writer)
- extension.extend_reader(self)
- end
- current_extension_name = nil
- if options.debugExtensions then
- local sorted_lhs = {}
- for lhs, _ in pairs(walkable_syntax) do
- table.insert(sorted_lhs, lhs)
- end
- table.sort(sorted_lhs)
-
- local output_lines = {"{"}
- for lhs_index, lhs in ipairs(sorted_lhs) do
- local encoded_lhs = util.encode_json_string(lhs)
- table.insert(output_lines, [[ ]] ..encoded_lhs .. [[: []])
- local rule = walkable_syntax[lhs]
- for rhs_index, rhs in ipairs(rule) do
- local human_readable_rhs
- if type(rhs) == "string" then
- human_readable_rhs = rhs
- else
- local pattern_name
- if rhs[3] then
- pattern_name = rhs[3]
- else
- pattern_name = "Anonymous Pattern"
- end
- local extension_name = rhs[2]
- human_readable_rhs = pattern_name .. [[ (]] .. extension_name .. [[)]]
- end
- local encoded_rhs = util.encode_json_string(human_readable_rhs)
- local output_line = [[ ]] .. encoded_rhs
- if rhs_index < #rule then
- output_line = output_line .. ","
- end
- table.insert(output_lines, output_line)
- end
- local output_line = " ]"
- if lhs_index < #sorted_lhs then
- output_line = output_line .. ","
- end
- table.insert(output_lines, output_line)
- end
- table.insert(output_lines, "}")
-
- local output = table.concat(output_lines, "\n")
- local output_filename = options.debugExtensionsFileName
- local output_file = assert(io.open(output_filename, "w"),
- [[Could not open file "]] .. output_filename .. [[" for writing]])
- assert(output_file:write(output))
- assert(output_file:close())
- end
- for lhs, rule in pairs(walkable_syntax) do
- syntax[lhs] = parsers.fail
- for _, rhs in ipairs(rule) do
- local pattern
- if type(rhs) == "string" then
- pattern = V(rhs)
- else
- pattern = rhs[1]
- if type(pattern) == "string" then
- pattern = V(pattern)
- end
- end
- syntax[lhs] = syntax[lhs] + pattern
- end
- end
- if options.underscores then
- self.add_special_character("_")
- end
-
- if not options.codeSpans then
- syntax.Code = parsers.fail
- else
- self.add_special_character("`")
- end
-
- if not options.html then
- syntax.DisplayHtml = parsers.fail
- syntax.InlineHtml = parsers.fail
- syntax.HtmlEntity = parsers.fail
- else
- self.add_special_character("&")
- end
-
- if options.preserveTabs then
- options.stripIndent = false
- end
-
- if not options.smartEllipses then
- syntax.Smart = parsers.fail
- else
- self.add_special_character(".")
- end
-
- if not options.relativeReferences then
- syntax.AutoLinkRelativeReference = parsers.fail
- end
-
- if options.contentLevel == "inline" then
- syntax[1] = "Inlines"
- syntax.Inlines = V("InitializeState")
- * parsers.Inline^0
- * ( parsers.spacing^0
- * parsers.eof / "")
- syntax.Space = parsers.Space + parsers.blankline / writer.space
- end
-
- local blocks_nested_t = util.table_copy(syntax)
- blocks_nested_t.ExpectedJekyllData = parsers.fail
- parsers.blocks_nested = Ct(blocks_nested_t)
-
- parsers.blocks = Ct(syntax)
-
- local inlines_t = util.table_copy(syntax)
- inlines_t[1] = "Inlines"
- inlines_t.Inlines = V("InitializeState")
- * parsers.Inline^0
- * ( parsers.spacing^0
- * parsers.eof / "")
- parsers.inlines = Ct(inlines_t)
-
- local inlines_no_inline_note_t = util.table_copy(inlines_t)
- inlines_no_inline_note_t.InlineNote = parsers.fail
- parsers.inlines_no_inline_note = Ct(inlines_no_inline_note_t)
-
- local inlines_no_html_t = util.table_copy(inlines_t)
- inlines_no_html_t.DisplayHtml = parsers.fail
- inlines_no_html_t.InlineHtml = parsers.fail
- inlines_no_html_t.HtmlEntity = parsers.fail
- parsers.inlines_no_html = Ct(inlines_no_html_t)
-
- local inlines_nbsp_t = util.table_copy(inlines_t)
- inlines_nbsp_t.Endline = parsers.NonbreakingEndline
- inlines_nbsp_t.Space = parsers.NonbreakingSpace
- parsers.inlines_nbsp = Ct(inlines_nbsp_t)
-
- local inlines_no_link_or_emphasis_t = util.table_copy(inlines_t)
- inlines_no_link_or_emphasis_t.LinkAndEmph = parsers.fail
- inlines_no_link_or_emphasis_t.EndlineExceptions = parsers.EndlineExceptions - parsers.eof
- parsers.inlines_no_link_or_emphasis = Ct(inlines_no_link_or_emphasis_t)
- return function(input)
- input = input:gsub("\r\n?", "\n")
- if input:sub(-1) ~= "\n" then
- input = input .. "\n"
- end
- references = {}
- local opt_string = {}
- for k, _ in pairs(defaultOptions) do
- local v = options[k]
- if type(v) == "table" then
- for _, i in ipairs(v) do
- opt_string[#opt_string+1] = k .. "=" .. tostring(i)
- end
- elseif k ~= "cacheDir" then
- opt_string[#opt_string+1] = k .. "=" .. tostring(v)
- end
- end
- table.sort(opt_string)
- local salt = table.concat(opt_string, ",") .. "," .. metadata.version
- local output
- local function convert(input)
- local document = self.parser_functions.parse_blocks(input)
- local output = util.rope_to_string(writer.document(document))
- local undosep_start, undosep_end
- local potential_secend_start, secend_start
- local potential_sep_start, sep_start
- while true do
- -- find a `writer->undosep`
- undosep_start, undosep_end = output:find(writer.undosep_text, 1, true)
- if undosep_start == nil then break end
- -- skip any preceding section ends
- secend_start = undosep_start
- while true do
- potential_secend_start = secend_start - #writer.secend_text
- if potential_secend_start < 1
- or output:sub(potential_secend_start, secend_start - 1) ~= writer.secend_text then
- break
- end
- secend_start = potential_secend_start
- end
- -- find an immediately preceding block element / paragraph separator
- sep_start = secend_start
- potential_sep_start = sep_start - #writer.interblocksep_text
- if potential_sep_start >= 1
- and output:sub(potential_sep_start, sep_start - 1) == writer.interblocksep_text then
- sep_start = potential_sep_start
- else
- potential_sep_start = sep_start - #writer.paragraphsep_text
- if potential_sep_start >= 1
- and output:sub(potential_sep_start, sep_start - 1) == writer.paragraphsep_text then
- sep_start = potential_sep_start
- end
- end
- -- remove `writer->undosep` and immediately preceding block element / paragraph separator
- output = output:sub(1, sep_start - 1)
- .. output:sub(secend_start, undosep_start - 1)
- .. output:sub(undosep_end + 1)
- end
- return output
- end
- if options.eagerCache or options.finalizeCache then
- local name = util.cache(options.cacheDir, input, salt, convert,
- ".md" .. writer.suffix)
- output = writer.pack(name)
- else
- output = convert(input)
- end
- if options.finalizeCache then
- local file, mode
- if options.frozenCacheCounter > 0 then
- mode = "a"
- else
- mode = "w"
- end
- file = assert(io.open(options.frozenCacheFileName, mode),
- [[Could not open file "]] .. options.frozenCacheFileName
- .. [[" for writing]])
- assert(file:write([[\expandafter\global\expandafter\def\csname ]]
- .. [[markdownFrozenCache]] .. options.frozenCacheCounter
- .. [[\endcsname{]] .. output .. [[}]] .. "\n"))
- assert(file:close())
- end
- return output
- end
- end
- return self
-end
-M.extensions = {}
-M.extensions.bracketed_spans = function()
- return {
- name = "built-in bracketed_spans syntax extension",
- extend_writer = function(self)
- function self.span(s, attr)
- if self.flatten_inlines then return s end
- return {"\\markdownRendererBracketedSpanAttributeContextBegin",
- self.attributes(attr),
- s,
- "\\markdownRendererBracketedSpanAttributeContextEnd{}"}
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
-
- local span_label = parsers.lbracket
- * (Cs((parsers.alphanumeric^1
- + parsers.inticks
- + parsers.autolink
- + V("InlineHtml")
- + ( parsers.backslash * parsers.backslash)
- + ( parsers.backslash * (parsers.lbracket + parsers.rbracket)
- + V("Space") + V("Endline")
- + (parsers.any
- - (parsers.newline + parsers.lbracket + parsers.rbracket
- + parsers.blankline^2))))^1)
- / self.parser_functions.parse_inlines)
- * parsers.rbracket
-
- local Span = span_label
- * Ct(parsers.attributes)
- / writer.span
-
- self.insert_pattern("Inline before LinkAndEmph",
- Span, "Span")
- end
- }
-end
-M.extensions.citations = function(citation_nbsps)
- return {
- name = "built-in citations syntax extension",
- extend_writer = function(self)
- function self.citations(text_cites, cites)
- local buffer = {}
- if self.flatten_inlines then
- for _,cite in ipairs(cites) do
- if cite.prenote then
- table.insert(buffer, {cite.prenote, " "})
- end
- table.insert(buffer, cite.name)
- if cite.postnote then
- table.insert(buffer, {" ", cite.postnote})
- end
- end
- else
- table.insert(buffer, {"\\markdownRenderer", text_cites and "TextCite" or "Cite",
- "{", #cites, "}"})
- for _,cite in ipairs(cites) do
- table.insert(buffer, {cite.suppress_author and "-" or "+", "{",
- cite.prenote or "", "}{", cite.postnote or "", "}{", cite.name, "}"})
- end
- end
- return buffer
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
-
- local citation_chars
- = parsers.alphanumeric
- + S("#$%&-+<>~/_")
-
- local citation_name
- = Cs(parsers.dash^-1) * parsers.at
- * Cs(citation_chars
- * (((citation_chars + parsers.internal_punctuation
- - parsers.comma - parsers.semicolon)
- * -#((parsers.internal_punctuation - parsers.comma
- - parsers.semicolon)^0
- * -(citation_chars + parsers.internal_punctuation
- - parsers.comma - parsers.semicolon)))^0
- * citation_chars)^-1)
-
- local citation_body_prenote
- = Cs((parsers.alphanumeric^1
- + parsers.bracketed
- + parsers.inticks
- + parsers.autolink
- + V("InlineHtml")
- + V("Space") + V("Endline")
- + (parsers.anyescaped
- - (parsers.newline + parsers.rbracket + parsers.blankline^2))
- - (parsers.spnl * parsers.dash^-1 * parsers.at))^1)
-
- local citation_body_postnote
- = Cs((parsers.alphanumeric^1
- + parsers.bracketed
- + parsers.inticks
- + parsers.autolink
- + V("InlineHtml")
- + V("Space") + V("Endline")
- + (parsers.anyescaped
- - (parsers.newline + parsers.rbracket + parsers.semicolon
- + parsers.blankline^2))
- - (parsers.spnl * parsers.rbracket))^1)
-
- local citation_body_chunk
- = ( citation_body_prenote
- * parsers.spnlc_sep
- + Cc("")
- * parsers.spnlc
- )
- * citation_name
- * (parsers.internal_punctuation - parsers.semicolon)^-1
- * ( parsers.spnlc
- * citation_body_postnote
- + Cc("")
- * parsers.spnlc
- )
-
- local citation_body
- = citation_body_chunk
- * ( parsers.semicolon
- * parsers.spnlc
- * citation_body_chunk
- )^0
-
- local citation_headless_body_postnote
- = Cs((parsers.alphanumeric^1
- + parsers.bracketed
- + parsers.inticks
- + parsers.autolink
- + V("InlineHtml")
- + V("Space") + V("Endline")
- + (parsers.anyescaped
- - (parsers.newline + parsers.rbracket + parsers.at
- + parsers.semicolon + parsers.blankline^2))
- - (parsers.spnl * parsers.rbracket))^0)
-
- local citation_headless_body
- = citation_headless_body_postnote
- * ( parsers.semicolon
- * parsers.spnlc
- * citation_body_chunk
- )^0
-
- local citations
- = function(text_cites, raw_cites)
- local function normalize(str)
- if str == "" then
- str = nil
- else
- str = (citation_nbsps and
- self.parser_functions.parse_inlines_nbsp or
- self.parser_functions.parse_inlines)(str)
- end
- return str
- end
-
- local cites = {}
- for i = 1,#raw_cites,4 do
- cites[#cites+1] = {
- prenote = normalize(raw_cites[i]),
- suppress_author = raw_cites[i+1] == "-",
- name = writer.identifier(raw_cites[i+2]),
- postnote = normalize(raw_cites[i+3]),
- }
- end
- return writer.citations(text_cites, cites)
- end
-
- local TextCitations
- = Ct((parsers.spnlc
- * Cc("")
- * citation_name
- * ((parsers.spnlc
- * parsers.lbracket
- * citation_headless_body
- * parsers.rbracket) + Cc("")))^1)
- / function(raw_cites)
- return citations(true, raw_cites)
- end
-
- local ParenthesizedCitations
- = Ct((parsers.spnlc
- * parsers.lbracket
- * citation_body
- * parsers.rbracket)^1)
- / function(raw_cites)
- return citations(false, raw_cites)
- end
-
- local Citations = TextCitations + ParenthesizedCitations
-
- self.insert_pattern("Inline before LinkAndEmph",
- Citations, "Citations")
-
- self.add_special_character("@")
- self.add_special_character("-")
- end
- }
-end
-M.extensions.content_blocks = function(language_map)
- local languages_json = (function()
- local base, prev, curr
- for _, pathname in ipairs{kpse.lookup(language_map, { all=true })} do
- local file = io.open(pathname, "r")
- if not file then goto continue end
- local input = assert(file:read("*a"))
- assert(file:close())
- local json = input:gsub('("[^\n]-"):','[%1]=')
- curr = load("_ENV = {}; return "..json)()
- if type(curr) == "table" then
- if base == nil then
- base = curr
- else
- setmetatable(prev, { __index = curr })
- end
- prev = curr
- end
- ::continue::
- end
- return base or {}
- end)()
-
- return {
- name = "built-in content_blocks syntax extension",
- extend_writer = function(self)
- function self.contentblock(src,suf,type,tit)
- if not self.is_writing then return "" end
- src = src.."."..suf
- suf = suf:lower()
- if type == "onlineimage" then
- return {"\\markdownRendererContentBlockOnlineImage{",suf,"}",
- "{",self.string(src),"}",
- "{",self.uri(src),"}",
- "{",self.string(tit or ""),"}"}
- elseif languages_json[suf] then
- return {"\\markdownRendererContentBlockCode{",suf,"}",
- "{",self.string(languages_json[suf]),"}",
- "{",self.string(src),"}",
- "{",self.uri(src),"}",
- "{",self.string(tit or ""),"}"}
- else
- return {"\\markdownRendererContentBlock{",suf,"}",
- "{",self.string(src),"}",
- "{",self.uri(src),"}",
- "{",self.string(tit or ""),"}"}
- end
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
-
- local contentblock_tail
- = parsers.optionaltitle
- * (parsers.newline + parsers.eof)
-
- -- case insensitive online image suffix:
- local onlineimagesuffix
- = (function(...)
- local parser = nil
- for _, suffix in ipairs({...}) do
- local pattern=nil
- for i=1,#suffix do
- local char=suffix:sub(i,i)
- char = S(char:lower()..char:upper())
- if pattern == nil then
- pattern = char
- else
- pattern = pattern * char
- end
- end
- if parser == nil then
- parser = pattern
- else
- parser = parser + pattern
- end
- end
- return parser
- end)("png", "jpg", "jpeg", "gif", "tif", "tiff")
-
- -- online image url for iA Writer content blocks with mandatory suffix,
- -- allowing nested brackets:
- local onlineimageurl
- = (parsers.less
- * Cs((parsers.anyescaped
- - parsers.more
- - parsers.spacing
- - #(parsers.period
- * onlineimagesuffix
- * parsers.more
- * contentblock_tail))^0)
- * parsers.period
- * Cs(onlineimagesuffix)
- * parsers.more
- + (Cs((parsers.inparens
- + (parsers.anyescaped
- - parsers.spacing
- - parsers.rparent
- - #(parsers.period
- * onlineimagesuffix
- * contentblock_tail)))^0)
- * parsers.period
- * Cs(onlineimagesuffix))
- ) * Cc("onlineimage")
-
- -- filename for iA Writer content blocks with mandatory suffix:
- local localfilepath
- = parsers.slash
- * Cs((parsers.anyescaped
- - parsers.tab
- - parsers.newline
- - #(parsers.period
- * parsers.alphanumeric^1
- * contentblock_tail))^1)
- * parsers.period
- * Cs(parsers.alphanumeric^1)
- * Cc("localfile")
-
- local ContentBlock
- = parsers.check_trail_no_rem
- * (localfilepath + onlineimageurl)
- * contentblock_tail
- / writer.contentblock
-
- self.insert_pattern("Block before Blockquote",
- ContentBlock, "ContentBlock")
- end
- }
-end
-M.extensions.definition_lists = function(tight_lists)
- return {
- name = "built-in definition_lists syntax extension",
- extend_writer = function(self)
- local function dlitem(term, defs)
- local retVal = {"\\markdownRendererDlItem{",term,"}"}
- for _, def in ipairs(defs) do
- retVal[#retVal+1] = {"\\markdownRendererDlDefinitionBegin ",def,
- "\\markdownRendererDlDefinitionEnd "}
- end
- retVal[#retVal+1] = "\\markdownRendererDlItemEnd "
- return retVal
- end
-
- function self.definitionlist(items,tight)
- if not self.is_writing then return "" end
- local buffer = {}
- for _,item in ipairs(items) do
- buffer[#buffer + 1] = dlitem(item.term, item.definitions)
- end
- if tight and tight_lists then
- return {"\\markdownRendererDlBeginTight\n", buffer,
- "\n\\markdownRendererDlEndTight"}
- else
- return {"\\markdownRendererDlBegin\n", buffer,
- "\n\\markdownRendererDlEnd"}
- end
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
-
- local defstartchar = S("~:")
-
- local defstart = parsers.check_trail_length(0) * defstartchar * #parsers.spacing
- * (parsers.tab + parsers.space^-3)
- + parsers.check_trail_length(1) * defstartchar * #parsers.spacing
- * (parsers.tab + parsers.space^-2)
- + parsers.check_trail_length(2) * defstartchar * #parsers.spacing
- * (parsers.tab + parsers.space^-1)
- + parsers.check_trail_length(3) * defstartchar * #parsers.spacing
-
- local indented_line = (parsers.check_minimal_indent / "") * parsers.check_code_trail * parsers.line
-
- local blank = parsers.check_minimal_blank_indent_and_any_trail * parsers.optionalspace * parsers.newline
-
- local dlchunk = Cs(parsers.line * (indented_line - blank)^0)
-
- local indented_blocks = function(bl)
- return Cs( bl
- * (blank^1 * (parsers.check_minimal_indent / "")
- * parsers.check_code_trail * -parsers.blankline * bl)^0
- * (blank^1 + parsers.eof))
- end
-
- local function definition_list_item(term, defs, _)
- return { term = self.parser_functions.parse_inlines(term),
- definitions = defs }
- end
-
- local DefinitionListItemLoose
- = C(parsers.line) * blank^0
- * Ct((parsers.check_minimal_indent * (defstart
- * indented_blocks(dlchunk)
- / self.parser_functions.parse_blocks_nested))^1)
- * Cc(false) / definition_list_item
-
- local DefinitionListItemTight
- = C(parsers.line)
- * Ct((parsers.check_minimal_indent * (defstart * dlchunk
- / self.parser_functions.parse_blocks_nested))^1)
- * Cc(true) / definition_list_item
-
- local DefinitionList
- = ( Ct(DefinitionListItemLoose^1) * Cc(false)
- + Ct(DefinitionListItemTight^1)
- * (blank^0
- * -DefinitionListItemLoose * Cc(true))
- ) / writer.definitionlist
-
- self.insert_pattern("Block after Heading",
- DefinitionList, "DefinitionList")
- end
- }
-end
-M.extensions.fancy_lists = function()
- return {
- name = "built-in fancy_lists syntax extension",
- extend_writer = function(self)
- local options = self.options
-
- function self.fancylist(items,tight,startnum,numstyle,numdelim)
- if not self.is_writing then return "" end
- local buffer = {}
- local num = startnum
- for _,item in ipairs(items) do
- if item ~= "" then
- buffer[#buffer + 1] = self.fancyitem(item,num)
- end
- if num ~= nil and item ~= "" then
- num = num + 1
- end
- end
- local contents = util.intersperse(buffer,"\n")
- if tight and options.tightLists then
- return {"\\markdownRendererFancyOlBeginTight{",
- numstyle,"}{",numdelim,"}",contents,
- "\n\\markdownRendererFancyOlEndTight "}
- else
- return {"\\markdownRendererFancyOlBegin{",
- numstyle,"}{",numdelim,"}",contents,
- "\n\\markdownRendererFancyOlEnd "}
- end
- end
- function self.fancyitem(s,num)
- if num ~= nil then
- return {"\\markdownRendererFancyOlItemWithNumber{",num,"}",s,
- "\\markdownRendererFancyOlItemEnd "}
- else
- return {"\\markdownRendererFancyOlItem ",s,"\\markdownRendererFancyOlItemEnd "}
- end
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local options = self.options
- local writer = self.writer
-
- local function combine_markers_and_delims(markers, delims)
- local markers_table = {}
- for _,marker in ipairs(markers) do
- local start_marker
- local continuation_marker
- if type(marker) == "table" then
- start_marker = marker[1]
- continuation_marker = marker[2]
- else
- start_marker = marker
- continuation_marker = marker
- end
- for _,delim in ipairs(delims) do
- table.insert(markers_table, {start_marker, continuation_marker, delim})
- end
- end
- return markers_table
- end
-
- local function join_table_with_func(func, markers_table)
- local pattern = func(table.unpack(markers_table[1]))
- for i = 2, #markers_table do
- pattern = pattern + func(table.unpack(markers_table[i]))
- end
- return pattern
- end
-
- local lowercase_letter_marker = R("az")
- local uppercase_letter_marker = R("AZ")
-
- local roman_marker = function(chars)
- local m, d, c = P(chars[1]), P(chars[2]), P(chars[3])
- local l, x, v, i = P(chars[4]), P(chars[5]), P(chars[6]), P(chars[7])
- return m^-3
- * (c*m + c*d + d^-1 * c^-3)
- * (x*c + x*l + l^-1 * x^-3)
- * (i*x + i*v + v^-1 * i^-3)
- end
-
- local lowercase_roman_marker = roman_marker({"m", "d", "c", "l", "x", "v", "i"})
- local uppercase_roman_marker = roman_marker({"M", "D", "C", "L", "X", "V", "I"})
-
- local lowercase_opening_roman_marker = P("i")
- local uppercase_opening_roman_marker = P("I")
-
- local digit_marker = parsers.dig * parsers.dig^-8
-
- local markers = {
- {lowercase_opening_roman_marker, lowercase_roman_marker},
- {uppercase_opening_roman_marker, uppercase_roman_marker},
- lowercase_letter_marker,
- uppercase_letter_marker,
- lowercase_roman_marker,
- uppercase_roman_marker,
- digit_marker
- }
-
- local delims = {
- parsers.period,
- parsers.rparent
- }
-
- local markers_table = combine_markers_and_delims(markers, delims)
-
- local function enumerator(start_marker, _, delimiter_type, interrupting)
- local delimiter_range
- local allowed_end
- if interrupting then
- delimiter_range = P("1")
- allowed_end = C(parsers.spacechar^1) * #parsers.linechar
- else
- delimiter_range = start_marker
- allowed_end = C(parsers.spacechar^1) + #(parsers.newline + parsers.eof)
- end
-
- return parsers.check_trail
- * Ct(C(delimiter_range) * C(delimiter_type))
- * allowed_end
- end
-
- local starter = join_table_with_func(enumerator, markers_table)
-
- local TightListItem = function(starter)
- return parsers.add_indent(starter, "li")
- * parsers.indented_content_tight
- end
-
- local LooseListItem = function(starter)
- return parsers.add_indent(starter, "li")
- * parsers.indented_content_loose
- * remove_indent("li")
- end
-
- local function roman2number(roman)
- local romans = { ["M"] = 1000, ["D"] = 500, ["C"] = 100, ["L"] = 50, ["X"] = 10, ["V"] = 5, ["I"] = 1 }
- local numeral = 0
-
- local i = 1
- local len = string.len(roman)
- while i < len do
- local z1, z2 = romans[ string.sub(roman, i, i) ], romans[ string.sub(roman, i+1, i+1) ]
- if z1 < z2 then
- numeral = numeral + (z2 - z1)
- i = i + 2
- else
- numeral = numeral + z1
- i = i + 1
- end
- end
- if i <= len then numeral = numeral + romans[ string.sub(roman,i,i) ] end
- return numeral
- end
-
- local function sniffstyle(numstr, delimend)
- local numdelim
- if delimend == ")" then
- numdelim = "OneParen"
- elseif delimend == "." then
- numdelim = "Period"
- else
- numdelim = "Default"
- end
-
- local num
- num = numstr:match("^([I])$")
- if num then
- return roman2number(num), "UpperRoman", numdelim
- end
- num = numstr:match("^([i])$")
- if num then
- return roman2number(string.upper(num)), "LowerRoman", numdelim
- end
- num = numstr:match("^([A-Z])$")
- if num then
- return string.byte(num) - string.byte("A") + 1, "UpperAlpha", numdelim
- end
- num = numstr:match("^([a-z])$")
- if num then
- return string.byte(num) - string.byte("a") + 1, "LowerAlpha", numdelim
- end
- num = numstr:match("^([IVXLCDM]+)")
- if num then
- return roman2number(num), "UpperRoman", numdelim
- end
- num = numstr:match("^([ivxlcdm]+)")
- if num then
- return roman2number(string.upper(num)), "LowerRoman", numdelim
- end
- return math.floor(tonumber(numstr) or 1), "Decimal", numdelim
- end
-
- local function fancylist(items,tight,start)
- local startnum, numstyle, numdelim = sniffstyle(start[2][1], start[2][2])
- return writer.fancylist(items,tight,
- options.startNumber and startnum or 1,
- numstyle or "Decimal",
- numdelim or "Default")
- end
-
- local FancyListOfType = function(start_marker, continuation_marker, delimiter_type)
- local enumerator_start = enumerator(start_marker, continuation_marker, delimiter_type)
- local enumerator_cont = enumerator(continuation_marker, continuation_marker, delimiter_type)
- return Cg(enumerator_start, "listtype")
- * (Ct( TightListItem(Cb("listtype"))
- * ((parsers.check_minimal_indent / "") * TightListItem(enumerator_cont))^0)
- * Cc(true)
- * -#((parsers.conditionally_indented_blankline^0 / "")
- * parsers.check_minimal_indent * enumerator_cont)
- + Ct( LooseListItem(Cb("listtype"))
- * ((parsers.conditionally_indented_blankline^0 / "")
- * (parsers.check_minimal_indent / "") * LooseListItem(enumerator_cont))^0)
- * Cc(false)
- ) * Ct(Cb("listtype")) / fancylist
- end
-
- local FancyList = join_table_with_func(FancyListOfType, markers_table)
-
- local Endline = parsers.newline
- * (parsers.check_minimal_indent
- * -parsers.EndlineExceptions
- + parsers.check_optional_indent
- * -parsers.EndlineExceptions
- * -starter)
- * parsers.spacechar^0
- / writer.soft_line_break
-
- self.update_rule("OrderedList", FancyList)
- self.update_rule("Endline", Endline)
- end
- }
-end
-M.extensions.fenced_code = function(blank_before_code_fence,
- allow_attributes,
- allow_raw_blocks)
- return {
- name = "built-in fenced_code syntax extension",
- extend_writer = function(self)
- local options = self.options
-
- function self.fencedCode(s, i, attr)
- if not self.is_writing then return "" end
- s = s:gsub("\n$", "")
- local buf = {}
- if attr ~= nil then
- table.insert(buf, {"\\markdownRendererFencedCodeAttributeContextBegin",
- self.attributes(attr)})
- end
- local name = util.cache_verbatim(options.cacheDir, s)
- table.insert(buf, {"\\markdownRendererInputFencedCode{",
- name,"}{",self.string(i),"}{",self.infostring(i),"}"})
- if attr ~= nil then
- table.insert(buf, "\\markdownRendererFencedCodeAttributeContextEnd{}")
- end
- return buf
- end
-
- if allow_raw_blocks then
- function self.rawBlock(s, attr)
- if not self.is_writing then return "" end
- s = s:gsub("\n$", "")
- local name = util.cache_verbatim(options.cacheDir, s)
- return {"\\markdownRendererInputRawBlock{",
- name,"}{", self.string(attr),"}"}
- end
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
-
- local function captures_geq_length(_,i,a,b)
- return #a >= #b and i
- end
-
- local function strip_enclosing_whitespaces(str)
- return str:gsub("^%s*(.-)%s*$", "%1")
- end
-
- local tilde_infostring = Cs(Cs((V("HtmlEntity")
- + parsers.anyescaped
- - parsers.newline)^0)
- / strip_enclosing_whitespaces)
-
- local backtick_infostring = Cs(Cs((V("HtmlEntity")
- + (-#(parsers.backslash * parsers.backtick) * parsers.anyescaped)
- - parsers.newline
- - parsers.backtick)^0)
- / strip_enclosing_whitespaces)
-
- local fenceindent
-
- local function has_trail(indent_table)
- return indent_table ~= nil and
- indent_table.trail ~= nil and
- next(indent_table.trail) ~= nil
- end
-
- local function has_indents(indent_table)
- return indent_table ~= nil and
- indent_table.indents ~= nil and
- next(indent_table.indents) ~= nil
- end
-
- local function get_last_indent_name(indent_table)
- if has_indents(indent_table) then
- return indent_table.indents[#indent_table.indents].name
- end
- end
-
- local function count_fenced_start_indent(_, _, indent_table, trail)
- local last_indent_name = get_last_indent_name(indent_table)
- fenceindent = 0
- if last_indent_name ~= "li" then
- fenceindent = #trail
- end
- return true
- end
-
- local fencehead = function(char, infostring)
- return Cmt(Cb("indent_info") * parsers.check_trail, count_fenced_start_indent)
- * Cg(char^3, "fencelength")
- * parsers.optionalspace
- * infostring
- * (parsers.newline + parsers.eof)
- end
-
- local fencetail = function(char)
- return parsers.check_trail_no_rem
- * Cmt(C(char^3) * Cb("fencelength"), captures_geq_length)
- * parsers.optionalspace * (parsers.newline + parsers.eof)
- + parsers.eof
- end
-
- local function process_fenced_line(s, i, indent_table, line_content, is_blank) -- luacheck: ignore s i
- local remainder = ""
- if has_trail(indent_table) then
- remainder = indent_table.trail.internal_remainder
- end
-
- if is_blank and get_last_indent_name(indent_table) == "li" then
- remainder = ""
- end
-
- local str = remainder .. line_content
- local index = 1
- local remaining = fenceindent
-
- while true do
- local c = str:sub(index, index)
- if c == " " and remaining > 0 then
- remaining = remaining - 1
- index = index + 1
- elseif c == "\t" and remaining > 3 then
- remaining = remaining - 4
- index = index + 1
- else
- break
- end
- end
-
- return true, str:sub(index)
- end
-
- local fencedline = function(char)
- return Cmt(Cb("indent_info") * C(parsers.line - fencetail(char)) * Cc(false), process_fenced_line)
- end
-
- local blankfencedline = Cmt(Cb("indent_info") * C(parsers.blankline) * Cc(true), process_fenced_line)
-
- local TildeFencedCode
- = fencehead(parsers.tilde, tilde_infostring)
- * Cs(((parsers.check_minimal_blank_indent / "") * blankfencedline
- + (parsers.check_minimal_indent / "") * fencedline(parsers.tilde))^0)
- * ((parsers.check_minimal_indent / "") * fencetail(parsers.tilde) + parsers.succeed)
-
- local BacktickFencedCode
- = fencehead(parsers.backtick, backtick_infostring)
- * Cs(((parsers.check_minimal_blank_indent / "") * blankfencedline
- + (parsers.check_minimal_indent / "") * fencedline(parsers.backtick))^0)
- * ((parsers.check_minimal_indent / "") * fencetail(parsers.backtick) + parsers.succeed)
-
- local infostring_with_attributes
- = Ct(C((parsers.linechar
- - ( parsers.optionalspace
- * parsers.attributes))^0)
- * parsers.optionalspace
- * Ct(parsers.attributes))
-
- local FencedCode
- = ((TildeFencedCode + BacktickFencedCode)
- / function(infostring, code)
- local expanded_code = self.expandtabs(code)
-
- if allow_raw_blocks then
- local raw_attr = lpeg.match(parsers.raw_attribute,
- infostring)
- if raw_attr then
- return writer.rawBlock(expanded_code, raw_attr)
- end
- end
-
- local attr = nil
- if allow_attributes then
- local match = lpeg.match(infostring_with_attributes,
- infostring)
- if match then
- infostring, attr = table.unpack(match)
- end
- end
- return writer.fencedCode(expanded_code, infostring, attr)
- end)
-
- self.insert_pattern("Block after Verbatim",
- FencedCode, "FencedCode")
-
- local fencestart
- if blank_before_code_fence then
- fencestart = parsers.fail
- else
- fencestart = fencehead(parsers.backtick, backtick_infostring)
- + fencehead(parsers.tilde, tilde_infostring)
- end
-
- self.update_rule("EndlineExceptions", function(previous_pattern)
- if previous_pattern == nil then
- previous_pattern = parsers.EndlineExceptions
- end
- return previous_pattern + fencestart
- end)
-
- self.add_special_character("`")
- self.add_special_character("~")
- end
- }
-end
-M.extensions.fenced_divs = function(blank_before_div_fence)
- return {
- name = "built-in fenced_divs syntax extension",
- extend_writer = function(self)
- function self.div_begin(attributes)
- local start_output = {"\\markdownRendererFencedDivAttributeContextBegin\n",
- self.attributes(attributes)}
- local end_output = {"\\markdownRendererFencedDivAttributeContextEnd{}"}
- return self.push_attributes("div", attributes, start_output, end_output)
- end
- function self.div_end()
- return self.pop_attributes("div")
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
- local fenced_div_infostring
- = C((parsers.linechar
- - ( parsers.spacechar^1
- * parsers.colon^1))^1)
-
- local fenced_div_begin = parsers.nonindentspace
- * parsers.colon^3
- * parsers.optionalspace
- * fenced_div_infostring
- * ( parsers.spacechar^1
- * parsers.colon^1)^0
- * parsers.optionalspace
- * (parsers.newline + parsers.eof)
-
- local fenced_div_end = parsers.nonindentspace
- * parsers.colon^3
- * parsers.optionalspace
- * (parsers.newline + parsers.eof)
- self.initialize_named_group("fenced_div_level", "0")
- self.initialize_named_group("fenced_div_num_opening_indents")
-
- local function increment_div_level()
- local function push_indent_table(s, i, indent_table, -- luacheck: ignore s i
- fenced_div_num_opening_indents, fenced_div_level)
- fenced_div_level = tonumber(fenced_div_level) + 1
- local num_opening_indents = 0
- if indent_table.indents ~= nil then
- num_opening_indents = #indent_table.indents
- end
- fenced_div_num_opening_indents[fenced_div_level] = num_opening_indents
- return true, fenced_div_num_opening_indents
- end
-
- local function increment_level(s, i, fenced_div_level) -- luacheck: ignore s i
- fenced_div_level = tonumber(fenced_div_level) + 1
- return true, tostring(fenced_div_level)
- end
-
- return Cg( Cmt( Cb("indent_info")
- * Cb("fenced_div_num_opening_indents")
- * Cb("fenced_div_level"), push_indent_table)
- , "fenced_div_num_opening_indents")
- * Cg( Cmt( Cb("fenced_div_level"), increment_level)
- , "fenced_div_level")
- end
-
- local function decrement_div_level()
- local function pop_indent_table(s, i, fenced_div_indent_table, fenced_div_level) -- luacheck: ignore s i
- fenced_div_level = tonumber(fenced_div_level)
- fenced_div_indent_table[fenced_div_level] = nil
- return true, tostring(fenced_div_level - 1)
- end
-
- return Cg( Cmt( Cb("fenced_div_num_opening_indents")
- * Cb("fenced_div_level"), pop_indent_table)
- , "fenced_div_level")
- end
-
- local non_fenced_div_block = parsers.check_minimal_indent * V("Block")
- - parsers.check_minimal_indent_and_trail * fenced_div_end
-
- local non_fenced_div_paragraph = parsers.check_minimal_indent * V("Paragraph")
- - parsers.check_minimal_indent_and_trail * fenced_div_end
-
- local blank = parsers.minimally_indented_blank
-
- local block_separated = parsers.block_sep_group(blank)
- * non_fenced_div_block
-
- local loop_body_pair = parsers.create_loop_body_pair(block_separated,
- non_fenced_div_paragraph,
- parsers.block_sep_group(blank),
- parsers.par_sep_group(blank))
-
- local content_loop = ( non_fenced_div_block
- * loop_body_pair.block^0
- + non_fenced_div_paragraph
- * block_separated
- * loop_body_pair.block^0
- + non_fenced_div_paragraph
- * loop_body_pair.par^0)
- * blank^0
-
- local FencedDiv = fenced_div_begin
- / function (infostring)
- local attr = lpeg.match(Ct(parsers.attributes), infostring)
- if attr == nil then
- attr = {"." .. infostring}
- end
- return attr
- end
- / writer.div_begin
- * increment_div_level()
- * parsers.skipblanklines
- * Ct(content_loop)
- * parsers.minimally_indented_blank^0
- * parsers.check_minimal_indent_and_trail * fenced_div_end
- * decrement_div_level()
- * (Cc("") / writer.div_end)
-
- self.insert_pattern("Block after Verbatim",
- FencedDiv, "FencedDiv")
-
- self.add_special_character(":")
-
- local function is_inside_div()
- local function check_div_level(s, i, fenced_div_level) -- luacheck: ignore s i
- fenced_div_level = tonumber(fenced_div_level)
- return fenced_div_level > 0
- end
-
- return Cmt(Cb("fenced_div_level"), check_div_level)
- end
-
- local function check_indent()
- local function compare_indent(s, i, indent_table, -- luacheck: ignore s i
- fenced_div_num_opening_indents, fenced_div_level)
- fenced_div_level = tonumber(fenced_div_level)
- local num_current_indents = (indent_table.current_line_indents ~= nil and
- #indent_table.current_line_indents) or 0
- local num_opening_indents = fenced_div_num_opening_indents[fenced_div_level]
- return num_current_indents == num_opening_indents
- end
-
- return Cmt( Cb("indent_info")
- * Cb("fenced_div_num_opening_indents")
- * Cb("fenced_div_level"), compare_indent)
- end
-
- local fencestart = is_inside_div()
- * fenced_div_end
- * check_indent()
-
- if not blank_before_div_fence then
- self.update_rule("EndlineExceptions", function(previous_pattern)
- if previous_pattern == nil then
- previous_pattern = parsers.EndlineExceptions
- end
- return previous_pattern + fencestart
- end)
- end
- end
- }
-end
-M.extensions.header_attributes = function()
- return {
- name = "built-in header_attributes syntax extension",
- extend_writer = function()
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
-
- local function strip_atx_end(s)
- return s:gsub("%s+#*%s*$","")
- end
-
- local AtxHeading = Cg(parsers.heading_start, "level")
- * parsers.optionalspace
- * (C(((parsers.linechar
- - (parsers.attributes
- * parsers.optionalspace
- * parsers.newline))
- * (parsers.linechar
- - parsers.lbrace)^0)^1)
- / strip_atx_end
- / parsers.parse_heading_text)
- * Cg(Ct(parsers.newline
- + (parsers.attributes
- * parsers.optionalspace
- * parsers.newline)), "attributes")
- * Cb("level")
- * Cb("attributes")
- / writer.heading
-
- local function strip_trailing_spaces(s)
- return s:gsub("%s*$","")
- end
-
- local heading_line = (parsers.linechar
- - (parsers.attributes
- * parsers.optionalspace
- * parsers.newline))^1
- - parsers.thematic_break_lines
-
- local heading_text = heading_line
- * ((V("Endline") / "\n") * (heading_line - parsers.heading_level))^0
- * parsers.newline^-1
-
- local SetextHeading = parsers.freeze_trail * parsers.check_trail_no_rem
- * #(heading_text
- * (parsers.attributes
- * parsers.optionalspace
- * parsers.newline)^-1
- * parsers.check_minimal_indent * parsers.check_trail * parsers.heading_level)
- * Cs(heading_text) / strip_trailing_spaces
- / parsers.parse_heading_text
- * Cg(Ct((parsers.attributes
- * parsers.optionalspace
- * parsers.newline)^-1), "attributes")
- * parsers.check_minimal_indent_and_trail * parsers.heading_level
- * Cb("attributes")
- * parsers.newline
- * parsers.unfreeze_trail
- / writer.heading
-
- local Heading = AtxHeading + SetextHeading
- self.update_rule("Heading", Heading)
- end
- }
-end
-M.extensions.inline_code_attributes = function()
- return {
- name = "built-in inline_code_attributes syntax extension",
- extend_writer = function()
- end, extend_reader = function(self)
- local writer = self.writer
-
- local CodeWithAttributes = parsers.inticks
- * Ct(parsers.attributes)
- / writer.code
-
- self.insert_pattern("Inline before Code",
- CodeWithAttributes,
- "CodeWithAttributes")
- end
- }
-end
-M.extensions.line_blocks = function()
- return {
- name = "built-in line_blocks syntax extension",
- extend_writer = function(self)
- function self.lineblock(lines)
- if not self.is_writing then return "" end
- local buffer = {}
- for i = 1, #lines - 1 do
- buffer[#buffer + 1] = { lines[i], self.hard_line_break }
- end
- buffer[#buffer + 1] = lines[#lines]
-
- return {"\\markdownRendererLineBlockBegin\n"
- ,buffer,
- "\n\\markdownRendererLineBlockEnd "}
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
-
- local LineBlock = Ct(
- (Cs(
- ( (parsers.pipe * parsers.space)/""
- * ((parsers.space)/entities.char_entity("nbsp"))^0
- * parsers.linechar^0 * (parsers.newline/""))
- * (-parsers.pipe
- * (parsers.space^1/" ")
- * parsers.linechar^1
- * (parsers.newline/"")
- )^0
- * (parsers.blankline/"")^0
- ) / self.parser_functions.parse_inlines)^1) / writer.lineblock
-
- self.insert_pattern("Block after Blockquote",
- LineBlock, "LineBlock")
- end
- }
-end
-M.extensions.mark = function()
- return {
- name = "built-in mark syntax extension",
- extend_writer = function(self)
- function self.mark(s)
- if self.flatten_inlines then return s end
- return {"\\markdownRendererMark{", s, "}"}
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
-
- local doubleequals = P("==")
-
- local Mark = parsers.between(V("Inline"), doubleequals, doubleequals)
- / function (inlines) return writer.mark(inlines) end
-
- self.add_special_character("=")
- self.insert_pattern("Inline before LinkAndEmph",
- Mark, "Mark")
- end
- }
-end
-M.extensions.link_attributes = function()
- return {
- name = "built-in link_attributes syntax extension",
- extend_writer = function()
- end, extend_reader = function(self)
- local parsers = self.parsers
- local options = self.options
-
- local define_reference_parser = (parsers.check_trail / "") * parsers.link_label * parsers.colon
- * parsers.spnlc * parsers.url
- * ( parsers.spnlc_sep * parsers.title * (parsers.spnlc * Ct(parsers.attributes))
- * parsers.only_blank
- + parsers.spnlc_sep * parsers.title * parsers.only_blank
- + Cc("") * (parsers.spnlc * Ct(parsers.attributes)) * parsers.only_blank
- + Cc("") * parsers.only_blank)
-
- local ReferenceWithAttributes = define_reference_parser
- / self.register_link
-
- self.update_rule("Reference", ReferenceWithAttributes)
-
-
- local LinkWithAttributesAndEmph = Ct(parsers.link_and_emph_table * Cg(Cc(true), "match_link_attributes"))
- / self.defer_link_and_emphasis_processing
-
- self.update_rule("LinkAndEmph", LinkWithAttributesAndEmph)
-
- local AutoLinkUrlWithAttributes
- = parsers.auto_link_url
- * Ct(parsers.attributes)
- / self.auto_link_url
-
- self.insert_pattern("Inline before AutoLinkUrl",
- AutoLinkUrlWithAttributes,
- "AutoLinkUrlWithAttributes")
-
- local AutoLinkEmailWithAttributes
- = parsers.auto_link_email
- * Ct(parsers.attributes)
- / self.auto_link_email
-
- self.insert_pattern("Inline before AutoLinkEmail",
- AutoLinkEmailWithAttributes,
- "AutoLinkEmailWithAttributes")
-
- if options.relativeReferences then
-
- local AutoLinkRelativeReferenceWithAttributes
- = parsers.auto_link_relative_reference
- * Ct(parsers.attributes)
- / self.auto_link_url
-
- self.insert_pattern(
- "Inline before AutoLinkRelativeReference",
- AutoLinkRelativeReferenceWithAttributes,
- "AutoLinkRelativeReferenceWithAttributes")
-
- end
-
- end
- }
-end
-M.extensions.notes = function(notes, inline_notes)
- assert(notes or inline_notes)
- return {
- name = "built-in notes syntax extension",
- extend_writer = function(self)
- function self.note(s)
- if self.flatten_inlines then return "" end
- return {"\\markdownRendererNote{",s,"}"}
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
-
- if inline_notes then
- local InlineNote
- = parsers.circumflex
- * (parsers.link_label / self.parser_functions.parse_inlines_no_inline_note)
- / writer.note
-
- self.insert_pattern("Inline after LinkAndEmph",
- InlineNote, "InlineNote")
- end
- if notes then
- local function strip_first_char(s)
- return s:sub(2)
- end
-
- local RawNoteRef
- = #(parsers.lbracket * parsers.circumflex)
- * parsers.link_label / strip_first_char
-
- local rawnotes = {}
-
- -- like indirect_link
- local function lookup_note(ref)
- return writer.defer_call(function()
- local found = rawnotes[self.normalize_tag(ref)]
- if found then
- return writer.note(
- self.parser_functions.parse_blocks_nested(found))
- else
- return {"[",
- self.parser_functions.parse_inlines("^" .. ref), "]"}
- end
- end)
- end
-
- local function register_note(ref,rawnote)
- local normalized_tag = self.normalize_tag(ref)
- if rawnotes[normalized_tag] == nil then
- rawnotes[normalized_tag] = rawnote
- end
- return ""
- end
-
- local NoteRef = RawNoteRef / lookup_note
-
- local optionally_indented_line = parsers.check_optional_indent_and_any_trail * parsers.line
-
- local blank = parsers.check_optional_blank_indent_and_any_trail * parsers.optionalspace * parsers.newline
-
- local chunk = Cs(parsers.line * (optionally_indented_line - blank)^0)
-
- local indented_blocks = function(bl)
- return Cs( bl
- * (blank^1 * (parsers.check_optional_indent / "")
- * parsers.check_code_trail * -parsers.blankline * bl)^0)
- end
-
- local NoteBlock
- = parsers.check_trail_no_rem * RawNoteRef * parsers.colon
- * parsers.spnlc * indented_blocks(chunk)
- / register_note
-
- local Reference = NoteBlock + parsers.Reference
-
- self.update_rule("Reference", Reference)
- self.insert_pattern("Inline before LinkAndEmph",
- NoteRef, "NoteRef")
- end
-
- self.add_special_character("^")
- end
- }
-end
-M.extensions.pipe_tables = function(table_captions, table_attributes)
-
- local function make_pipe_table_rectangular(rows)
- local num_columns = #rows[2]
- local rectangular_rows = {}
- for i = 1, #rows do
- local row = rows[i]
- local rectangular_row = {}
- for j = 1, num_columns do
- rectangular_row[j] = row[j] or ""
+function util.salt(options)
+ local opt_string = {}
+ for k, _ in pairs(defaultOptions) do
+ local v = options[k]
+ if type(v) == "table" then
+ for _, i in ipairs(v) do
+ opt_string[#opt_string+1] = k .. "=" .. tostring(i)
end
- table.insert(rectangular_rows, rectangular_row)
+ elseif k ~= "cacheDir" then
+ opt_string[#opt_string+1] = k .. "=" .. tostring(v)
end
- return rectangular_rows
end
-
- local function pipe_table_row(allow_empty_first_column
- , nonempty_column
- , column_separator
- , column)
- local row_beginning
- if allow_empty_first_column then
- row_beginning = -- empty first column
- #(parsers.spacechar^4
- * column_separator)
- * parsers.optionalspace
- * column
- * parsers.optionalspace
- -- non-empty first column
- + parsers.nonindentspace
- * nonempty_column^-1
- * parsers.optionalspace
- else
- row_beginning = parsers.nonindentspace
- * nonempty_column^-1
- * parsers.optionalspace
- end
-
- return Ct(row_beginning
- * (-- single column with no leading pipes
- #(column_separator
- * parsers.optionalspace
- * parsers.newline)
- * column_separator
- * parsers.optionalspace
- -- single column with leading pipes or
- -- more than a single column
- + (column_separator
- * parsers.optionalspace
- * column
- * parsers.optionalspace)^1
- * (column_separator
- * parsers.optionalspace)^-1))
- end
-
- return {
- name = "built-in pipe_tables syntax extension",
- extend_writer = function(self)
- function self.table(rows, caption, attributes)
- if not self.is_writing then return "" end
- local buffer = {}
- if attributes ~= nil then
- table.insert(buffer,
- "\\markdownRendererTableAttributeContextBegin\n")
- table.insert(buffer, self.attributes(attributes))
- end
- table.insert(buffer,
- {"\\markdownRendererTable{",
- caption or "", "}{", #rows - 1, "}{",
- #rows[1], "}"})
- local temp = rows[2] -- put alignments on the first row
- rows[2] = rows[1]
- rows[1] = temp
- for i, row in ipairs(rows) do
- table.insert(buffer, "{")
- for _, column in ipairs(row) do
- if i > 1 then -- do not use braces for alignments
- table.insert(buffer, "{")
- end
- table.insert(buffer, column)
- if i > 1 then
- table.insert(buffer, "}")
- end
- end
- table.insert(buffer, "}")
- end
- if attributes ~= nil then
- table.insert(buffer,
- "\\markdownRendererTableAttributeContextEnd{}")
- end
- return buffer
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
-
- local table_hline_separator = parsers.pipe + parsers.plus
-
- local table_hline_column = (parsers.dash
- - #(parsers.dash
- * (parsers.spacechar
- + table_hline_separator
- + parsers.newline)))^1
- * (parsers.colon * Cc("r")
- + parsers.dash * Cc("d"))
- + parsers.colon
- * (parsers.dash
- - #(parsers.dash
- * (parsers.spacechar
- + table_hline_separator
- + parsers.newline)))^1
- * (parsers.colon * Cc("c")
- + parsers.dash * Cc("l"))
-
- local table_hline = pipe_table_row(false
- , table_hline_column
- , table_hline_separator
- , table_hline_column)
-
- local table_caption_beginning = (parsers.check_minimal_blank_indent_and_any_trail_no_rem
- * parsers.optionalspace * parsers.newline)^0
- * parsers.check_minimal_indent_and_trail
- * (P("Table")^-1 * parsers.colon)
- * parsers.optionalspace
-
- local function strip_trailing_spaces(s)
- return s:gsub("%s*$","")
- end
-
- local table_row = pipe_table_row(true
- , (C((parsers.linechar - parsers.pipe)^1)
- / strip_trailing_spaces
- / self.parser_functions.parse_inlines)
- , parsers.pipe
- , (C((parsers.linechar - parsers.pipe)^0)
- / strip_trailing_spaces
- / self.parser_functions.parse_inlines))
-
- local table_caption
- if table_captions then
- table_caption = #table_caption_beginning
- * table_caption_beginning
- if table_attributes then
- table_caption = table_caption
- * (C(((( parsers.linechar
- - (parsers.attributes
- * parsers.optionalspace
- * parsers.newline
- * -#( parsers.optionalspace
- * parsers.linechar)))
- + ( parsers.newline
- * #( parsers.optionalspace
- * parsers.linechar)
- * C(parsers.optionalspace) / writer.space))
- * (parsers.linechar
- - parsers.lbrace)^0)^1)
- / self.parser_functions.parse_inlines)
- * (parsers.newline
- + ( Ct(parsers.attributes)
- * parsers.optionalspace
- * parsers.newline))
- else
- table_caption = table_caption
- * C(( parsers.linechar
- + ( parsers.newline
- * #( parsers.optionalspace
- * parsers.linechar)
- * C(parsers.optionalspace) / writer.space))^1)
- / self.parser_functions.parse_inlines
- * parsers.newline
- end
- else
- table_caption = parsers.fail
- end
-
- local PipeTable = Ct(table_row * parsers.newline * (parsers.check_minimal_indent_and_trail / {})
- * table_hline * parsers.newline
- * ((parsers.check_minimal_indent / {}) * table_row * parsers.newline)^0)
- / make_pipe_table_rectangular
- * table_caption^-1
- / writer.table
-
- self.insert_pattern("Block after Blockquote",
- PipeTable, "PipeTable")
- end
- }
+ table.sort(opt_string)
+ local salt = table.concat(opt_string, ",")
+ .. "," .. metadata.version
+ return salt
end
-M.extensions.raw_inline = function()
- return {
- name = "built-in raw_inline syntax extension",
- extend_writer = function(self)
- local options = self.options
-
- function self.rawInline(s, attr)
- if not self.is_writing then return "" end
- if self.flatten_inlines then return s end
- local name = util.cache_verbatim(options.cacheDir, s)
- return {"\\markdownRendererInputRawInline{",
- name,"}{", self.string(attr),"}"}
- end
- end, extend_reader = function(self)
- local writer = self.writer
-
- local RawInline = parsers.inticks
- * parsers.raw_attribute
- / writer.rawInline
-
- self.insert_pattern("Inline before Code",
- RawInline, "RawInline")
- end
- }
-end
-M.extensions.strike_through = function()
- return {
- name = "built-in strike_through syntax extension",
- extend_writer = function(self)
- function self.strike_through(s)
- if self.flatten_inlines then return s end
- return {"\\markdownRendererStrikeThrough{",s,"}"}
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
-
- local StrikeThrough = (
- parsers.between(parsers.Inline, parsers.doubletildes,
- parsers.doubletildes)
- ) / writer.strike_through
-
- self.insert_pattern("Inline after LinkAndEmph",
- StrikeThrough, "StrikeThrough")
-
- self.add_special_character("~")
- end
- }
-end
-M.extensions.subscripts = function()
- return {
- name = "built-in subscripts syntax extension",
- extend_writer = function(self)
- function self.subscript(s)
- if self.flatten_inlines then return s end
- return {"\\markdownRendererSubscript{",s,"}"}
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
-
- local Subscript = (
- parsers.between(parsers.Str, parsers.tilde, parsers.tilde)
- ) / writer.subscript
-
- self.insert_pattern("Inline after LinkAndEmph",
- Subscript, "Subscript")
-
- self.add_special_character("~")
- end
- }
+local function warn(s)
+ io.stderr:write("Warning: " .. s .. "\n")
end
-M.extensions.superscripts = function()
- return {
- name = "built-in superscripts syntax extension",
- extend_writer = function(self)
- function self.superscript(s)
- if self.flatten_inlines then return s end
- return {"\\markdownRendererSuperscript{",s,"}"}
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
-
- local Superscript = (
- parsers.between(parsers.Str, parsers.circumflex, parsers.circumflex)
- ) / writer.superscript
-
- self.insert_pattern("Inline after LinkAndEmph",
- Superscript, "Superscript")
-
- self.add_special_character("^")
- end
- }
-end
-M.extensions.tex_math = function(tex_math_dollars,
- tex_math_single_backslash,
- tex_math_double_backslash)
- return {
- name = "built-in tex_math syntax extension",
- extend_writer = function(self)
- function self.display_math(s)
- if self.flatten_inlines then return s end
- return {"\\markdownRendererDisplayMath{",self.math(s),"}"}
- end
- function self.inline_math(s)
- if self.flatten_inlines then return s end
- return {"\\markdownRendererInlineMath{",self.math(s),"}"}
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
-
- local function between(p, starter, ender)
- return (starter * Cs(p * (p - ender)^0) * ender)
- end
-
- local function strip_preceding_whitespaces(str)
- return str:gsub("^%s*(.-)$", "%1")
- end
-
- local allowed_before_closing = B( parsers.backslash * parsers.any
- + parsers.any * (parsers.any - parsers.backslash))
-
- local allowed_before_closing_no_space = B( parsers.backslash * parsers.any
- + parsers.any * (parsers.nonspacechar - parsers.backslash))
-
- local dollar_math_content = (parsers.newline * (parsers.check_optional_indent / "")
- + parsers.backslash^-1
- * parsers.linechar)
- - parsers.blankline^2
- - parsers.dollar
-
- local inline_math_opening_dollars = parsers.dollar
- * #(parsers.nonspacechar)
-
- local inline_math_closing_dollars = allowed_before_closing_no_space
- * parsers.dollar
- * -#(parsers.digit)
-
- local inline_math_dollars = between(Cs( dollar_math_content),
- inline_math_opening_dollars,
- inline_math_closing_dollars)
-
- local display_math_opening_dollars = parsers.dollar
- * parsers.dollar
-
- local display_math_closing_dollars = parsers.dollar
- * parsers.dollar
-
- local display_math_dollars = between(Cs( dollar_math_content),
- display_math_opening_dollars,
- display_math_closing_dollars)
- local backslash_math_content = (parsers.newline * (parsers.check_optional_indent / "")
- + parsers.linechar)
- - parsers.blankline^2
- local inline_math_opening_double = parsers.backslash
- * parsers.backslash
- * parsers.lparent
-
- local inline_math_closing_double = allowed_before_closing
- * parsers.spacechar^0
- * parsers.backslash
- * parsers.backslash
- * parsers.rparent
-
- local inline_math_double = between(Cs( backslash_math_content),
- inline_math_opening_double,
- inline_math_closing_double)
- / strip_preceding_whitespaces
-
- local display_math_opening_double = parsers.backslash
- * parsers.backslash
- * parsers.lbracket
-
- local display_math_closing_double = allowed_before_closing
- * parsers.spacechar^0
- * parsers.backslash
- * parsers.backslash
- * parsers.rbracket
-
- local display_math_double = between(Cs( backslash_math_content),
- display_math_opening_double,
- display_math_closing_double)
- / strip_preceding_whitespaces
- local inline_math_opening_single = parsers.backslash
- * parsers.lparent
-
- local inline_math_closing_single = allowed_before_closing
- * parsers.spacechar^0
- * parsers.backslash
- * parsers.rparent
-
- local inline_math_single = between(Cs( backslash_math_content),
- inline_math_opening_single,
- inline_math_closing_single)
- / strip_preceding_whitespaces
-
- local display_math_opening_single = parsers.backslash
- * parsers.lbracket
- local display_math_closing_single = allowed_before_closing
- * parsers.spacechar^0
- * parsers.backslash
- * parsers.rbracket
-
- local display_math_single = between(Cs( backslash_math_content),
- display_math_opening_single,
- display_math_closing_single)
- / strip_preceding_whitespaces
-
- local display_math = parsers.fail
-
- local inline_math = parsers.fail
-
- if tex_math_dollars then
- display_math = display_math + display_math_dollars
- inline_math = inline_math + inline_math_dollars
- end
-
- if tex_math_double_backslash then
- display_math = display_math + display_math_double
- inline_math = inline_math + inline_math_double
- end
-
- if tex_math_single_backslash then
- display_math = display_math + display_math_single
- inline_math = inline_math + inline_math_single
- end
-
- local TexMath = display_math / writer.display_math
- + inline_math / writer.inline_math
-
- self.insert_pattern("Inline after LinkAndEmph",
- TexMath, "TexMath")
-
- if tex_math_dollars then
- self.add_special_character("$")
- end
-
- if tex_math_single_backslash or tex_math_double_backslash then
- self.add_special_character("\\")
- self.add_special_character("[")
- self.add_special_character("]")
- self.add_special_character(")")
- self.add_special_character("(")
- end
- end
- }
-end
-M.extensions.jekyll_data = function(expect_jekyll_data)
- return {
- name = "built-in jekyll_data syntax extension",
- extend_writer = function(self)
- function self.jekyllData(d, t, p)
- if not self.is_writing then return "" end
-
- local buf = {}
-
- local keys = {}
- for k, _ in pairs(d) do
- table.insert(keys, k)
- end
- table.sort(keys)
-
- if not p then
- table.insert(buf, "\\markdownRendererJekyllDataBegin")
- end
-
- if #d > 0 then
- table.insert(buf, "\\markdownRendererJekyllDataSequenceBegin{")
- table.insert(buf, self.identifier(p or "null"))
- table.insert(buf, "}{")
- table.insert(buf, #keys)
- table.insert(buf, "}")
- else
- table.insert(buf, "\\markdownRendererJekyllDataMappingBegin{")
- table.insert(buf, self.identifier(p or "null"))
- table.insert(buf, "}{")
- table.insert(buf, #keys)
- table.insert(buf, "}")
- end
-
- for _, k in ipairs(keys) do
- local v = d[k]
- local typ = type(v)
- k = tostring(k or "null")
- if typ == "table" and next(v) ~= nil then
- table.insert(
- buf,
- self.jekyllData(v, t, k)
- )
- else
- k = self.identifier(k)
- v = tostring(v)
- if typ == "boolean" then
- table.insert(buf, "\\markdownRendererJekyllDataBoolean{")
- table.insert(buf, k)
- table.insert(buf, "}{")
- table.insert(buf, v)
- table.insert(buf, "}")
- elseif typ == "number" then
- table.insert(buf, "\\markdownRendererJekyllDataNumber{")
- table.insert(buf, k)
- table.insert(buf, "}{")
- table.insert(buf, v)
- table.insert(buf, "}")
- elseif typ == "string" then
- table.insert(buf, "\\markdownRendererJekyllDataString{")
- table.insert(buf, k)
- table.insert(buf, "}{")
- table.insert(buf, t(v))
- table.insert(buf, "}")
- elseif typ == "table" then
- table.insert(buf, "\\markdownRendererJekyllDataEmpty{")
- table.insert(buf, k)
- table.insert(buf, "}")
- else
- error(format("Unexpected type %s for value of " ..
- "YAML key %s", typ, k))
- end
- end
- end
-
- if #d > 0 then
- table.insert(buf, "\\markdownRendererJekyllDataSequenceEnd")
- else
- table.insert(buf, "\\markdownRendererJekyllDataMappingEnd")
- end
-
- if not p then
- table.insert(buf, "\\markdownRendererJekyllDataEnd")
- end
-
- return buf
- end
- end, extend_reader = function(self)
- local parsers = self.parsers
- local writer = self.writer
-
- local JekyllData
- = Cmt( C((parsers.line - P("---") - P("..."))^0)
- , function(s, i, text) -- luacheck: ignore s i
- local data
- local ran_ok, _ = pcall(function()
- -- TODO: Replace with `require("tinyyaml")` in TeX Live 2023
- local tinyyaml = require("markdown-tinyyaml")
- data = tinyyaml.parse(text, {timestamps=false})
- end)
- if ran_ok and data ~= nil then
- return true, writer.jekyllData(data, function(s)
- return self.parser_functions.parse_blocks_nested(s)
- end, nil)
- else
- return false
- end
- end
- )
-
- local UnexpectedJekyllData
- = P("---")
- * parsers.blankline / 0
- * #(-parsers.blankline) -- if followed by blank, it's thematic break
- * JekyllData
- * (P("---") + P("..."))
-
- local ExpectedJekyllData
- = ( P("---")
- * parsers.blankline / 0
- * #(-parsers.blankline) -- if followed by blank, it's thematic break
- )^-1
- * JekyllData
- * (P("---") + P("..."))^-1
-
- self.insert_pattern("Block before Blockquote",
- UnexpectedJekyllData, "UnexpectedJekyllData")
- if expect_jekyll_data then
- self.update_rule("ExpectedJekyllData", ExpectedJekyllData)
- end
- end
- }
-end
function M.new(options)
options = options or {}
setmetatable(options, { __index = function (_, key)
return defaultOptions[key] end })
- if options.singletonCache and singletonCache.convert then
- for k, v in pairs(defaultOptions) do
- if type(v) == "table" then
- for i = 1, math.max(#singletonCache.options[k], #options[k]) do
- if singletonCache.options[k][i] ~= options[k][i] then
- goto miss
- end
- end
- elseif singletonCache.options[k] ~= options[k] then
- goto miss
- end
- end
- return singletonCache.convert
- end
- ::miss::
- local extensions = {}
-
- if options.bracketedSpans then
- local bracketed_spans_extension = M.extensions.bracketed_spans()
- table.insert(extensions, bracketed_spans_extension)
- end
-
- if options.contentBlocks then
- local content_blocks_extension = M.extensions.content_blocks(
- options.contentBlocksLanguageMap)
- table.insert(extensions, content_blocks_extension)
- end
-
- if options.definitionLists then
- local definition_lists_extension = M.extensions.definition_lists(
- options.tightLists)
- table.insert(extensions, definition_lists_extension)
- end
-
- if options.fencedCode then
- local fenced_code_extension = M.extensions.fenced_code(
- options.blankBeforeCodeFence,
- options.fencedCodeAttributes,
- options.rawAttribute)
- table.insert(extensions, fenced_code_extension)
- end
-
- if options.fencedDivs then
- local fenced_div_extension = M.extensions.fenced_divs(
- options.blankBeforeDivFence)
- table.insert(extensions, fenced_div_extension)
- end
-
- if options.headerAttributes then
- local header_attributes_extension = M.extensions.header_attributes()
- table.insert(extensions, header_attributes_extension)
- end
-
- if options.inlineCodeAttributes then
- local inline_code_attributes_extension =
- M.extensions.inline_code_attributes()
- table.insert(extensions, inline_code_attributes_extension)
- end
-
- if options.jekyllData then
- local jekyll_data_extension = M.extensions.jekyll_data(
- options.expectJekyllData)
- table.insert(extensions, jekyll_data_extension)
- end
-
- if options.linkAttributes then
- local link_attributes_extension =
- M.extensions.link_attributes()
- table.insert(extensions, link_attributes_extension)
- end
-
- if options.lineBlocks then
- local line_block_extension = M.extensions.line_blocks()
- table.insert(extensions, line_block_extension)
- end
-
- if options.mark then
- local mark_extension = M.extensions.mark()
- table.insert(extensions, mark_extension)
- end
-
- if options.pipeTables then
- local pipe_tables_extension = M.extensions.pipe_tables(
- options.tableCaptions, options.tableAttributes)
- table.insert(extensions, pipe_tables_extension)
- end
-
- if options.rawAttribute then
- local raw_inline_extension = M.extensions.raw_inline()
- table.insert(extensions, raw_inline_extension)
- end
-
- if options.strikeThrough then
- local strike_through_extension = M.extensions.strike_through()
- table.insert(extensions, strike_through_extension)
- end
-
- if options.subscripts then
- local subscript_extension = M.extensions.subscripts()
- table.insert(extensions, subscript_extension)
- end
-
- if options.superscripts then
- local superscript_extension = M.extensions.superscripts()
- table.insert(extensions, superscript_extension)
- end
-
- if options.texMathDollars or
- options.texMathSingleBackslash or
- options.texMathDoubleBackslash then
- local tex_math_extension = M.extensions.tex_math(
- options.texMathDollars,
- options.texMathSingleBackslash,
- options.texMathDoubleBackslash)
- table.insert(extensions, tex_math_extension)
- end
-
- if options.notes or options.inlineNotes then
- local notes_extension = M.extensions.notes(
- options.notes, options.inlineNotes)
- table.insert(extensions, notes_extension)
- end
-
- if options.citations then
- local citations_extension = M.extensions.citations(options.citationNbsps)
- table.insert(extensions, citations_extension)
- end
-
- if options.fancyLists then
- local fancy_lists_extension = M.extensions.fancy_lists()
- table.insert(extensions, fancy_lists_extension)
- end
- for _, user_extension_filename in ipairs(options.extensions) do
- local user_extension = (function(filename)
- local pathname = kpse.lookup(filename)
- local input_file = assert(io.open(pathname, "r"),
- [[Could not open user-defined syntax extension "]]
- .. pathname .. [[" for reading]])
- local input = assert(input_file:read("*a"))
- assert(input_file:close())
- local user_extension, err = load([[
- local sandbox = {}
- setmetatable(sandbox, {__index = _G})
- _ENV = sandbox
- ]] .. input)()
- assert(user_extension,
- [[Failed to compile user-defined syntax extension "]]
- .. pathname .. [[": ]] .. (err or [[]]))
- assert(user_extension.api_version ~= nil,
- [[User-defined syntax extension "]] .. pathname
- .. [[" does not specify mandatory field "api_version"]])
- assert(type(user_extension.api_version) == "number",
- [[User-defined syntax extension "]] .. pathname
- .. [[" specifies field "api_version" of type "]]
- .. type(user_extension.api_version)
- .. [[" but "number" was expected]])
- assert(user_extension.api_version > 0
- and user_extension.api_version <= metadata.user_extension_api_version,
- [[User-defined syntax extension "]] .. pathname
- .. [[" uses syntax extension API version "]]
- .. user_extension.api_version .. [[ but markdown.lua ]]
- .. metadata.version .. [[ uses API version ]]
- .. metadata.user_extension_api_version
- .. [[, which is incompatible]])
-
- assert(user_extension.grammar_version ~= nil,
- [[User-defined syntax extension "]] .. pathname
- .. [[" does not specify mandatory field "grammar_version"]])
- assert(type(user_extension.grammar_version) == "number",
- [[User-defined syntax extension "]] .. pathname
- .. [[" specifies field "grammar_version" of type "]]
- .. type(user_extension.grammar_version)
- .. [[" but "number" was expected]])
- assert(user_extension.grammar_version == metadata.grammar_version,
- [[User-defined syntax extension "]] .. pathname
- .. [[" uses grammar version "]] .. user_extension.grammar_version
- .. [[ but markdown.lua ]] .. metadata.version
- .. [[ uses grammar version ]] .. metadata.grammar_version
- .. [[, which is incompatible]])
-
- assert(user_extension.finalize_grammar ~= nil,
- [[User-defined syntax extension "]] .. pathname
- .. [[" does not specify mandatory "finalize_grammar" field]])
- assert(type(user_extension.finalize_grammar) == "function",
- [[User-defined syntax extension "]] .. pathname
- .. [[" specifies field "finalize_grammar" of type "]]
- .. type(user_extension.finalize_grammar)
- .. [[" but "function" was expected]])
- local extension = {
- name = [[user-defined "]] .. pathname .. [[" syntax extension]],
- extend_reader = user_extension.finalize_grammar,
- extend_writer = function() end,
- }
- return extension
- end)(user_extension_filename)
- table.insert(extensions, user_extension)
- end
- local writer = M.writer.new(options)
- local reader = M.reader.new(writer, options)
- local convert = reader.finalize_grammar(extensions)
- collectgarbage("collect")
- if options.singletonCache then
- local singletonCacheOptions = {}
- for k, v in pairs(options) do
- singletonCacheOptions[k] = v
+ local parser_convert = nil
+ return function(input)
+ local function convert(input)
+ if parser_convert == nil then
+ local parser = require("markdown-parser")
+ if metadata.version ~= parser.metadata.version then
+ warn("markdown.lua " .. metadata.version .. " used with " ..
+ "markdown-parser.lua " .. parser.metadata.version .. ".")
+ end
+ parser_convert = parser.new(options)
+ end
+ return parser_convert(input)
+ end
+ local output
+ if options.eagerCache or options.finalizeCache then
+ local salt = util.salt(options)
+ local name = util.cache(options.cacheDir, input, salt, convert,
+ ".md.tex")
+ output = [[\input{]] .. name .. [[}\relax]]
+ else
+ output = convert(input)
+ end
+ if options.finalizeCache then
+ local file, mode
+ if options.frozenCacheCounter > 0 then
+ mode = "a"
+ else
+ mode = "w"
+ end
+ file = assert(io.open(options.frozenCacheFileName, mode),
+ [[Could not open file "]] .. options.frozenCacheFileName
+ .. [[" for writing]])
+ assert(file:write(
+ [[\expandafter\global\expandafter\def\csname ]]
+ .. [[markdownFrozenCache]] .. options.frozenCacheCounter
+ .. [[\endcsname{]] .. output .. [[}]] .. "\n"))
+ assert(file:close())
end
- setmetatable(singletonCacheOptions,
- { __index = function (_, key)
- return defaultOptions[key] end })
- singletonCache.options = singletonCacheOptions
- singletonCache.convert = convert
+ return output
end
- return convert
end
-
return M
diff --git a/Master/texmf-dist/tex/luatex/nodetree/nodetree-embed.sty b/Master/texmf-dist/tex/luatex/nodetree/nodetree-embed.sty
index ddff12f436d..ec7ed8bd4bb 100644
--- a/Master/texmf-dist/tex/luatex/nodetree/nodetree-embed.sty
+++ b/Master/texmf-dist/tex/luatex/nodetree/nodetree-embed.sty
@@ -8,7 +8,7 @@
%%
%% This is a generated file.
%%
-%% Copyright (C) 2016-2023 by Josef Friedrich <josef@friedrich.rocks>
+%% Copyright (C) 2016-2024 by Josef Friedrich <josef@friedrich.rocks>
%% ----------------------------------------------------------------------
%% This work may be distributed and/or modified under the conditions of
%% the LaTeX Project Public License, either version 1.3c of this license
@@ -22,7 +22,7 @@
%%
\NeedsTeXFormat{LaTeX2e}[1994/06/01]
\ProvidesPackage{nodetree-embed}
- [2023/09/10 v2.3.0 Embed node trees into a LaTeX document]
+ [2024/09/17 v2.4.0 Embed node trees into a LaTeX document]
\RequirePackage{xcolor,mdframed,expl3,xparse,fontspec}
\input{nodetree}
\RequirePackage{kvoptions}
diff --git a/Master/texmf-dist/tex/luatex/nodetree/nodetree.lua b/Master/texmf-dist/tex/luatex/nodetree/nodetree.lua
index 18a1f204c34..82a3e294d33 100644
--- a/Master/texmf-dist/tex/luatex/nodetree/nodetree.lua
+++ b/Master/texmf-dist/tex/luatex/nodetree/nodetree.lua
@@ -30,7 +30,7 @@
--- be either `continue` or `stop`.
if not modules then modules = {} end modules ['nodetree'] = {
- version = '2.3.0',
+ version = '2.4.0',
comment = 'nodetree',
author = 'Josef Friedrich',
copyright = 'Josef Friedrich',
@@ -649,30 +649,37 @@ end
--- Convert a Lua table into a format string.
---
----@param table table # A table to generate an inline view of.
+---@param tbl table # A table to generate an inline view of.
---
---@return string
-function template.table_inline(table)
+function template.table_inline(tbl)
local tex_escape = ''
if options.channel == 'tex' then
tex_escape = '\\'
end
- if type(table) == 'table' then
- table = get_all_table_data(table)
+ if type(tbl) == 'table' then
+ tbl = get_all_table_data(tbl)
local output = tex_escape .. '{'
local kv_list = ''
- for key, value in pairs(table) do
- if type(key) ~= 'numbers' then
- key = '\'' ..
- template.colored_string(key, 'cyan', 'dim') .. '\''
- end
- kv_list = kv_list .. '[' .. key .. '] = ' ..
- template.table_inline(value) .. ', '
+ local keys = {}
+ for key in pairs(tbl) do
+ keys[#keys + 1] = key
+ end
+ table.sort(keys)
+ for i = 1, #keys do
+ local key = keys[i]
+ local value = tbl[key]
+ if type(key) ~= 'numbers' then
+ key = '\'' ..
+ template.colored_string(key, 'cyan', 'dim') .. '\''
+ end
+ kv_list = kv_list .. '[' .. key .. '] = ' ..
+ template.table_inline(value) .. ', '
end
output = output .. kv_list:gsub(', $', '')
return output .. tex_escape .. '}'
else
- return tostring(table)
+ return tostring(tbl)
end
end
diff --git a/Master/texmf-dist/tex/luatex/nodetree/nodetree.sty b/Master/texmf-dist/tex/luatex/nodetree/nodetree.sty
index a450ccdf022..f27e9c856c7 100644
--- a/Master/texmf-dist/tex/luatex/nodetree/nodetree.sty
+++ b/Master/texmf-dist/tex/luatex/nodetree/nodetree.sty
@@ -8,7 +8,7 @@
%%
%% This is a generated file.
%%
-%% Copyright (C) 2016-2023 by Josef Friedrich <josef@friedrich.rocks>
+%% Copyright (C) 2016-2024 by Josef Friedrich <josef@friedrich.rocks>
%% ----------------------------------------------------------------------
%% This work may be distributed and/or modified under the conditions of
%% the LaTeX Project Public License, either version 1.3c of this license
@@ -22,7 +22,7 @@
%%
\NeedsTeXFormat{LaTeX2e}[1999/12/01]
\ProvidesPackage{nodetree}
- [2023/09/10 v2.3.0 Visualize node lists in a tree view]
+ [2024/09/17 v2.4.0 Visualize node lists in a tree view]
\input{nodetree}
\RequirePackage{kvoptions}
\SetupKeyvalOptions{
diff --git a/Master/texmf-dist/tex/luatex/nodetree/nodetree.tex b/Master/texmf-dist/tex/luatex/nodetree/nodetree.tex
index 919ea275f7a..180bb1fb7c4 100644
--- a/Master/texmf-dist/tex/luatex/nodetree/nodetree.tex
+++ b/Master/texmf-dist/tex/luatex/nodetree/nodetree.tex
@@ -8,7 +8,7 @@
%%
%% This is a generated file.
%%
-%% Copyright (C) 2016-2023 by Josef Friedrich <josef@friedrich.rocks>
+%% Copyright (C) 2016-2024 by Josef Friedrich <josef@friedrich.rocks>
%% ----------------------------------------------------------------------
%% This work may be distributed and/or modified under the conditions of
%% the LaTeX Project Public License, either version 1.3c of this license
diff --git a/Master/texmf-dist/tex/luatex/penlight/penlight.lua b/Master/texmf-dist/tex/luatex/penlight/penlight.lua
index 6ffcaf49b70..e104886a83f 100644
--- a/Master/texmf-dist/tex/luatex/penlight/penlight.lua
+++ b/Master/texmf-dist/tex/luatex/penlight/penlight.lua
@@ -275,7 +275,7 @@ function Doc:reset()
end
---- Append a child to the currrent Node (ignoring current position).
+--- Append a child to the current Node (ignoring current position).
-- @param child a child node (either text or a document)
-- @return the current node (`self`)
-- @usage
@@ -311,7 +311,7 @@ end
--- Set attributes of a document node.
--- Will add/overwite values, but will not remove existing ones.
+-- Will add/overwrite values, but will not remove existing ones.
-- Operates on the Node itself, will not take position into account.
-- @tparam table t a table containing attribute/value pairs
-- @return the current node (`self`)
@@ -447,7 +447,7 @@ do
-- @param self document node to traverse
-- @param tag tag-name to look for
-- @param list array table to add the matching ones to
- -- @param recurse if truthy, recursivly search the node
+ -- @param recurse if truthy, recursively search the node
local function _children_with_name(self, tag, list, recurse)
-- TODO: protect against recursion
for _, child in ipairs(self) do
@@ -942,7 +942,7 @@ local html_empty_elements = { --lists all HTML empty (void) elements
}
--- Parse a well-formed HTML file as a string.
--- Tags are case-insenstive, DOCTYPE is ignored, and empty elements can be .. empty.
+-- Tags are case-insensitive, DOCTYPE is ignored, and empty elements can be .. empty.
-- @param s the HTML
function _M.parsehtml(s)
return _M.basic_parse(s,false,true)
@@ -1335,7 +1335,7 @@ end
-- Multiple short args can be combined like so: ( `-abcd`).
--
-- When specifying the `flags_valid` parameter, its contents can also contain
--- aliasses, to convert short/long flags to the same output name. See the
+-- aliases, to convert short/long flags to the same output name. See the
-- example below.
--
-- Note: if a flag is repeated, the last value wins.
@@ -1354,7 +1354,7 @@ end
-- { "hello", "world" }, -- list of flags taking values
-- { "l", "a", "b"}) -- list of allowed flags (value ones will be added)
--
--- -- More complex example using aliasses:
+-- -- More complex example using aliases:
-- local valid = {
-- long = "l", -- if 'l' is specified, it is reported as 'long'
-- new = { "n", "old" }, -- here both 'n' and 'old' will go into 'new'
@@ -1397,16 +1397,16 @@ function app.parse_args (args,flags_with_values, flags_valid)
valid = setmetatable({},{ __index = function(_, key) return key end })
else
valid = {}
- for k,aliasses in pairs(flags_valid) do
+ for k,aliases in pairs(flags_valid) do
if type(k) == "number" then -- array/list entry
- k = aliasses
+ k = aliases
end
- if type(aliasses) == "string" then -- single alias
- aliasses = { aliasses }
+ if type(aliases) == "string" then -- single alias
+ aliases = { aliases }
end
- if type(aliasses) == "table" then -- list of aliasses
+ if type(aliases) == "table" then -- list of aliases
-- it's the alternate name, so add the proper mappings
- for i, alias in ipairs(aliasses) do
+ for i, alias in ipairs(aliases) do
valid[alias] = k
end
end
@@ -1427,7 +1427,7 @@ function app.parse_args (args,flags_with_values, flags_valid)
end
-- now check that all flags with values are reported as such under all
- -- of their aliasses
+ -- of their aliases
for k, main_alias in pairs(valid) do
if with_values[main_alias] then
with_values[k] = true
@@ -1696,7 +1696,7 @@ function array2d.flatten (t)
return makelist(res)
end
---- reshape a 2D array. Reshape the aray by specifying a new nr of rows.
+--- reshape a 2D array. Reshape the array by specifying a new nr of rows.
-- @array2d t 2d array
-- @int nrows new number of rows
-- @bool co use column-order (Fortran-style) (default false)
@@ -1773,7 +1773,7 @@ end
--- extract the specified columns.
-- @array2d t 2d array
-- @tparam {int} cidx a table of column indices
--- @return a new 2d array with the extracted colums
+-- @return a new 2d array with the extracted columns
function array2d.extract_cols (t,cidx)
assert_arg(1,t,'table')
local res = {}
@@ -2097,7 +2097,7 @@ end,
--------------------
-- Module: 'pl.class'
--------------------
---- Provides a reuseable and convenient framework for creating classes in Lua.
+--- Provides a reusable and convenient framework for creating classes in Lua.
-- Two possible notations:
--
-- B = class(A)
@@ -2124,7 +2124,7 @@ local function call_ctor (c,obj,...)
init = rawget(parent_with_init, '_init')
parent_with_init = rawget(parent_with_init, '_parent_with_init')
end
- if parent_with_init then -- super() points to one above whereever _init came from
+ if parent_with_init then -- super() points to one above wherever _init came from
rawset(obj,'super',function(obj,...)
call_ctor(parent_with_init,obj,...)
end)
@@ -2970,9 +2970,9 @@ end
local config = {}
---- like `io.lines`, but allows for lines to be continued with '`\`'.
+--- like `io.lines`, but allows for lines to be continued with '`\\`'.
-- @param file a file-like object (anything where read() returns the next line) or a filename.
--- Defaults to stardard input.
+-- Defaults to standard input.
-- @return an iterator over the lines, or nil
-- @return error 'not a file-like object' or 'file is nil'
function config.lines(file)
@@ -3353,7 +3353,7 @@ function data.read(file,cnfg)
-- note that using dot as the thousands separator (@thousands_dot)
-- requires a special conversion function! For CSV, _empty fields_ are
- -- considered to default to numerial zeroes.
+ -- considered to default to numerical zeroes.
local tonumber = tonumber
local function try_number(x)
if thousands_dot then x = x:gsub('%.(...)','%1') end
@@ -5327,7 +5327,7 @@ function repr (e,lastpred)
end
func.repr = repr
--- collect all the non-PE values in this PE into vlist, and replace each occurence
+-- collect all the non-PE values in this PE into vlist, and replace each occurrence
-- with a constant PH (_C1, etc). Return the maximum placeholder index found.
local collect_values
function collect_values (e,vlist)
@@ -5411,13 +5411,20 @@ utils.add_function_factory(_PEMT,func.I)
func.bind1 = utils.bind1
func.curry = func.bind1
---- create a function which chains two functions.
+--- create a function which chains multiple functions.
-- @func f a function of at least one argument
-- @func g a function of at least one argument
+-- @param ... additional functions to compose
-- @return a function
--- @usage printf = compose(io.write,string.format)
-function func.compose (f,g)
- return function(...) return f(g(...)) end
+-- @usage printf = compose(io.write, string.format)
+-- @usage printf = compose(io.write, string.lower, string.format)
+function func.compose (...)
+ local args = pack(...)
+ return tablex.reduce(function(f, g)
+ return function(...)
+ return f(g(...))
+ end
+ end, args)
end
--- bind the arguments of a function to given values.
@@ -5475,7 +5482,7 @@ end,
--------------------
--------------
-- PL loader, for loading all PL libraries, only on demand.
--- Whenever a module is implicitly accesssed, the table will have the module automatically injected.
+-- Whenever a module is implicitly accessed, the table will have the module automatically injected.
-- (e.g. `_ENV.tablex`)
-- then that module is dynamically loaded. The submodules are all brought into
-- the table that is provided as the argument, or returned in a new table.
@@ -5573,7 +5580,7 @@ end,
--------------------
--------------
-- Entry point for loading all PL libraries only on demand, into the global space.
--- Requiring 'pl' means that whenever a module is implicitly accesssed
+-- Requiring 'pl' means that whenever a module is implicitly accessed
-- (e.g. `utils.split`)
-- then that module is dynamically loaded. The submodules are all brought into
-- the global space.
@@ -6872,7 +6879,7 @@ function List:insert(i, x)
return self
end
---- Insert an item at the begining of the list.
+--- Insert an item at the beginning of the list.
-- @param x a data item
-- @return the list
function List:put (x)
@@ -7282,7 +7289,7 @@ function List:iter ()
return iter(self)
end
---- Create an iterator over a seqence.
+--- Create an iterator over a sequence.
-- This captures the Python concept of 'sequence'.
-- For tables, iterates over all values with integer indices.
-- @param seq a sequence; a string (over characters), a table, a file object (over lines) or an iterator function
@@ -7637,10 +7644,14 @@ local function makelist(t)
return setmetatable(t, require('pl.List'))
end
---- list of keys.
+--- return a List of all keys.
+-- @class function
+-- @name Map:keys
Map.keys = tablex.keys
---- list of values.
+--- return a List of all values.
+-- @class function
+-- @name Map:values
Map.values = tablex.values
--- return an iterator over all key-value pairs.
@@ -7648,7 +7659,7 @@ function Map:iter ()
return pairs(self)
end
---- return a List of all key-value pairs, sorted by the keys.
+--- return a List of all key-value pairs, sorted by the keys in ascending order.
function Map:items()
local ls = makelist(tablex.pairmap (function (k,v) return makelist {k,v} end, self))
ls:sort(function(t1,t2) return t1[1] < t2[1] end)
@@ -8223,12 +8234,12 @@ local function err_func(name, param, err, code)
end
--- Lua iterator over the entries of a given directory.
--- Implicit link to [`luafilesystem.dir`](https://keplerproject.github.io/luafilesystem/manual.html#reference)
+-- Implicit link to [`luafilesystem.dir`](https://lunarmodules.github.io/luafilesystem/manual.html#dir)
-- @function dir
path.dir = lfs.dir
--- Creates a directory.
--- Implicit link to [`luafilesystem.mkdir`](https://keplerproject.github.io/luafilesystem/manual.html#reference)
+-- Implicit link to [`luafilesystem.mkdir`](https://lunarmodules.github.io/luafilesystem/manual.html#mkdir)
-- @function mkdir
path.mkdir = function(d)
local ok, err, code = lfs.mkdir(d)
@@ -8239,7 +8250,7 @@ path.mkdir = function(d)
end
--- Removes a directory.
--- Implicit link to [`luafilesystem.rmdir`](https://keplerproject.github.io/luafilesystem/manual.html#reference)
+-- Implicit link to [`luafilesystem.rmdir`](https://lunarmodules.github.io/luafilesystem/manual.html#rmdir)
-- @function rmdir
path.rmdir = function(d)
local ok, err, code = lfs.rmdir(d)
@@ -8250,7 +8261,7 @@ path.rmdir = function(d)
end
--- Gets attributes.
--- Implicit link to [`luafilesystem.attributes`](https://keplerproject.github.io/luafilesystem/manual.html#reference)
+-- Implicit link to [`luafilesystem.attributes`](https://lunarmodules.github.io/luafilesystem/manual.html#attributes)
-- @function attrib
path.attrib = function(d, r)
local ok, err, code = attrib(d, r)
@@ -8261,7 +8272,7 @@ path.attrib = function(d, r)
end
--- Get the working directory.
--- Implicit link to [`luafilesystem.currentdir`](https://keplerproject.github.io/luafilesystem/manual.html#reference)
+-- Implicit link to [`luafilesystem.currentdir`](https://lunarmodules.github.io/luafilesystem/manual.html#currentdir)
-- @function currentdir
path.currentdir = function()
local ok, err, code = currentdir()
@@ -8272,7 +8283,7 @@ path.currentdir = function()
end
--- Gets symlink attributes.
--- Implicit link to [`luafilesystem.symlinkattributes`](https://keplerproject.github.io/luafilesystem/manual.html#reference)
+-- Implicit link to [`luafilesystem.symlinkattributes`](https://lunarmodules.github.io/luafilesystem/manual.html#symlinkattributes)
-- @function link_attrib
path.link_attrib = function(d, r)
local ok, err, code = link_attrib(d, r)
@@ -8285,7 +8296,7 @@ end
--- Changes the working directory.
-- On Windows, if a drive is specified, it also changes the current drive. If
-- only specifying the drive, it will only switch drive, but not modify the path.
--- Implicit link to [`luafilesystem.chdir`](https://keplerproject.github.io/luafilesystem/manual.html#reference)
+-- Implicit link to [`luafilesystem.chdir`](https://lunarmodules.github.io/luafilesystem/manual.html#chdir)
-- @function chdir
path.chdir = function(d)
local ok, err, code = lfs.chdir(d)
@@ -8329,7 +8340,7 @@ end
--- does a path exist?
-- @string P A file path
--- @return the file path if it exists (either as file, directory, socket, etc), nil otherwise
+-- @return the file path if it exists (either as file, directory, socket, etc), false otherwise
function path.exists(P)
assert_string(1,P)
return attrib(P,'mode') ~= nil and P
@@ -8426,8 +8437,8 @@ end
-- @string[opt] pwd optional start path to use (default is current dir)
function path.abspath(P,pwd)
assert_string(1,P)
- if pwd then assert_string(2,pwd) end
local use_pwd = pwd ~= nil
+ if use_pwd then assert_string(2,pwd) end
if not use_pwd and not currentdir() then return P end
P = P:gsub('[\\/]$','')
pwd = pwd or currentdir()
@@ -8671,17 +8682,35 @@ end
-- In windows, if HOME isn't set, then USERPROFILE is used in preference to
-- HOMEDRIVE HOMEPATH. This is guaranteed to be writeable on all versions of Windows.
-- @string P A file path
+-- @treturn[1] string The file path with the `~` prefix substituted, or the input path if it had no prefix.
+-- @treturn[2] nil
+-- @treturn[2] string Error message if the environment variables were unavailable.
function path.expanduser(P)
assert_string(1,P)
- if at(P,1) == '~' then
- local home = getenv('HOME')
- if not home then -- has to be Windows
- home = getenv 'USERPROFILE' or (getenv 'HOMEDRIVE' .. getenv 'HOMEPATH')
- end
- return home..sub(P,2)
- else
+ if P:sub(1,1) ~= '~' then
return P
end
+
+ local home = getenv('HOME')
+ if (not home) and (not path.is_windows) then
+ -- no more options to try on Nix
+ return nil, "failed to expand '~' (HOME not set)"
+ end
+
+ if (not home) then
+ -- try alternatives on Windows
+ home = getenv 'USERPROFILE'
+ if not home then
+ local hd = getenv 'HOMEDRIVE'
+ local hp = getenv 'HOMEPATH'
+ if not (hd and hp) then
+ return nil, "failed to expand '~' (HOME, USERPROFILE, and HOMEDRIVE and/or HOMEPATH not set)"
+ end
+ home = hd..hp
+ end
+ end
+
+ return home..sub(P,2)
end
@@ -8839,7 +8868,7 @@ end
--- an iterator over all permutations of the elements of the given lists.
-- @param ... list-like tables, they are nil-safe if a length-field `n` is provided (see `utils.pack`)
--- @return an iterator which provides the next permutation as return values in the same order as the provided lists, preceeded by an index
+-- @return an iterator which provides the next permutation as return values in the same order as the provided lists, preceded by an index
-- @usage
-- local strs = utils.pack("one", nil, "three") -- adds an 'n' field for nil-safety
-- local bools = utils.pack(true, false)
@@ -8977,6 +9006,42 @@ local assert_arg = utils.assert_arg
local original_tostring = tostring
+-- Calculate min and max integer supported by lua_Number
+-- Assumptions:
+-- 1. max_int = 2 ^ n - 1
+-- 2. min_int = -max_int
+-- 3. if n > max_int versions with integer support will have
+-- integer overflow and versions without integers will lose least significant bit
+-- Note: if lua_Integer is smaller than lua_Number mantissa string.format('%d')
+-- can throw runtime error
+local max_int, min_int
+local next_cand = 1
+while next_cand > 0 and next_cand % 2 == 1 do
+ max_int = next_cand
+ min_int = -next_cand
+ next_cand = next_cand * 2 + 1
+end
+
+local function is_integer(value)
+ if _VERSION == "Lua 5.3" or _VERSION == "Lua 5.4" then
+ return mtype(value) == "integer"
+ end
+ if value < min_int or value > max_int then
+ return false
+ end
+ return math.floor(value) == value
+end
+
+local function is_float(value)
+ if _VERSION == "Lua 5.3" or _VERSION == "Lua 5.4" then
+ return mtype(value) == "float"
+ end
+ if value < min_int or value > max_int then
+ return true
+ end
+ return mfloor(value) == value
+end
+
-- Patch tostring to format numbers with better precision
-- and to produce cross-platform results for
-- infinite values and NaN.
@@ -8989,11 +9054,11 @@ local function tostring(value)
return "Inf"
elseif value == -mhuge then
return "-Inf"
- elseif (_VERSION ~= "Lua 5.3" or mtype(value) == "integer") and mfloor(value) == value then
+ elseif is_integer(value) then
return ("%d"):format(value)
else
local res = ("%.14g"):format(value)
- if _VERSION == "Lua 5.3" and mtype(value) == "float" and not res:find("%.") then
+ if is_float(value) and not res:find("%.") then
-- Number is internally a float but looks like an integer.
-- Insert ".0" after first run of digits.
res = res:gsub("%d+", "%0.0", 1)
@@ -11289,7 +11354,7 @@ local function _partition(p,delim,fn)
end
end
---- partition the string using first occurance of a delimiter
+--- partition the string using first occurrence of a delimiter
-- @string s the string
-- @string ch delimiter (match as plain string, no patterns)
-- @return part before ch
@@ -11303,7 +11368,7 @@ function stringx.partition(s,ch)
return _partition(s,ch,stringx.lfind)
end
---- partition the string p using last occurance of a delimiter
+--- partition the string p using last occurrence of a delimiter
-- @string s the string
-- @string ch delimiter (match as plain string, no patterns)
-- @return part before ch
@@ -11575,7 +11640,7 @@ end
---- Miscelaneous
+--- Miscellaneous
-- @section misc
--- return an iterator over all lines in a string
@@ -11593,7 +11658,7 @@ function stringx.lines(s)
return s:gmatch('([^\n]*)\n')
end
---- inital word letters uppercase ('title case').
+--- initial word letters uppercase ('title case').
-- Here 'words' mean chunks of non-space characters.
-- @string s the string
-- @return a string with each word's first letter uppercase
@@ -11614,7 +11679,7 @@ do
--- Return a shortened version of a string.
-- Fits string within w characters. Removed characters are marked with ellipsis.
-- @string s the string
- -- @int w the maxinum size allowed
+ -- @int w the maximum size allowed
-- @bool tail true if we want to show the end of the string (head otherwise)
-- @usage ('1234567890'):shorten(8) == '12345...'
-- @usage ('1234567890'):shorten(8, true) == '...67890'
@@ -11688,7 +11753,7 @@ end
--- Python-style formatting operator.
-- Calling `text.format_operator()` overloads the % operator for strings to give
--- Python/Ruby style formated output.
+-- Python/Ruby style formatted output.
-- This is extended to also do template-like substitution for map-like data.
--
-- Note this goes further than the original, and will allow these cases:
@@ -11698,7 +11763,7 @@ end
-- 3. a map of var=value pairs
-- 4. a function, as in gsub
--
--- For the second two cases, it uses $-variable substituion.
+-- For the second two cases, it uses $-variable substitution.
--
-- When called, this function will monkey-patch the global `string` metatable by
-- adding a `__mod` method.
@@ -12799,59 +12864,72 @@ end,
local utils = require 'pl.utils'
-local append,format,strsub,strfind,strgsub = table.insert,string.format,string.sub,string.find,string.gsub
+local append, concat = table.insert, table.concat
+local format, strsub, strfind, strgsub, strrep = string.format, string.sub, string.find, string.gsub, string.rep
-local APPENDER = "\n__R_size = __R_size + 1; __R_table[__R_size] = "
+local APPENDER = " __R_size = __R_size + 1; __R_table[__R_size] = "
+-- When this function returns, `pieces` is guaranteed to hold a complete Lua
+-- statement, meaning that new statements can be appended without creating
+-- invalid Lua code.
local function parseDollarParen(pieces, chunk, exec_pat, newline)
local s = 1
for term, executed, e in chunk:gmatch(exec_pat) do
- executed = '('..strsub(executed,2,-2)..')'
- append(pieces, APPENDER..format("%q", strsub(chunk,s, term - 1)))
- append(pieces, APPENDER..format("__tostring(%s or '')", executed))
+ executed = '(' .. strsub(executed, 2, -2) .. ')'
+ append(pieces, APPENDER .. format("%q;", strsub(chunk, s, term - 1)))
+ append(pieces, APPENDER .. format("__tostring(%s or '');", executed))
s = e
end
- local r
+ local remainder, newlines_removed
if newline then
- r = format("%q", strgsub(strsub(chunk,s),"\n",""))
+ remainder, newlines_removed = strgsub(strsub(chunk, s), "\n", "")
else
- r = format("%q", strsub(chunk,s))
+ remainder, newlines_removed = strsub(chunk, s), 0
end
- if r ~= '""' then
- append(pieces, APPENDER..r)
+ if remainder ~= "" then
+ append(pieces, APPENDER .. format("%q;", remainder))
+ end
+ if newlines_removed > 0 then
+ append(pieces, strrep("\n", newlines_removed))
end
end
-local function parseHashLines(chunk,inline_escape,brackets,esc,newline)
- local exec_pat = "()"..inline_escape.."(%b"..brackets..")()"
+local function parseHashLines(chunk, inline_escape, brackets, esc, newline)
+ -- Escape special characters to avoid invalid expressions
+ inline_escape = utils.escape(inline_escape)
+ esc = utils.escape(esc)
+
+ local exec_pat = "()" .. inline_escape .. "(%b" .. brackets .. ")()"
- local esc_pat = esc.."+([^\n]*\n?)"
- local esc_pat1, esc_pat2 = "^"..esc_pat, "\n"..esc_pat
- local pieces, s = {"return function()\nlocal __R_size, __R_table, __tostring = 0, {}, __tostring", n = 1}, 1
+ local esc_pat = esc .. "+([^\n]*\n?)"
+ local esc_pat1, esc_pat2 = "^" .. esc_pat, "\n" .. esc_pat
+ local pieces, s = {"return function() local __R_size, __R_table, __tostring = 0, {}, __tostring; "}, 1
while true do
- local _, e, lua = strfind(chunk,esc_pat1, s)
+ local _, e, lua = strfind(chunk, esc_pat1, s)
if not e then
local ss
- ss, e, lua = strfind(chunk,esc_pat2, s)
- parseDollarParen(pieces, strsub(chunk,s, ss), exec_pat, newline)
+ ss, e, lua = strfind(chunk, esc_pat2, s)
+ parseDollarParen(pieces, strsub(chunk, s, ss), exec_pat, newline)
if not e then break end
end
- if strsub(lua, -1, -1) == "\n" then lua = strsub(lua, 1, -2) end
- append(pieces, "\n"..lua)
+ if strsub(lua, -1, -1) ~= "\n" then lua = lua .. "\n" end -- Ensure trailing newline
+ append(pieces, lua)
+ -- since `lua` ends with a newline, there is no danger of subsequent
+ -- statements being gobbled up by comments or being altered
s = e + 1
end
- append(pieces, "\nreturn __R_table\nend")
+ append(pieces, "return __R_table; end")
-- let's check for a special case where there is nothing to template, but it's
-- just a single static string
local short = false
- if (#pieces == 3) and (pieces[2]:find(APPENDER, 1, true) == 1) then
- pieces = { "return " .. pieces[2]:sub(#APPENDER+1,-1) }
+ if (#pieces == 3) and (strfind(pieces[2], APPENDER, 1, true) == 1) then
+ pieces = { "return " .. strsub(pieces[2], #APPENDER + 1, -1) }
short = true
end
-- if short == true, the generated function will not return a table of strings,
-- but a single string
- return table.concat(pieces), short
+ return concat(pieces), short
end
local template = {}
@@ -12859,33 +12937,34 @@ local template = {}
--- expand the template using the specified environment.
-- This function will compile and render the template. For more performant
-- recurring usage use the two step approach by using `compile` and `ct:render`.
--- There are six special fields in the environment table `env`
---
--- * `_parent`: continue looking up in this table (e.g. `_parent=_G`).
--- * `_brackets`: bracket pair that wraps inline Lua expressions, default is '()'.
--- * `_escape`: character marking Lua lines, default is '#'
--- * `_inline_escape`: character marking inline Lua expression, default is '$'.
--- * `_chunk_name`: chunk name for loaded templates, used if there
--- is an error in Lua code. Default is 'TMP'.
--- * `_debug`: if truthy, the generated code will be printed upon a render error
---
-- @string str the template string
--- @tab[opt] env the environment
--- @return `rendered template + nil + source_code`, or `nil + error + source_code`. The last
--- return value (`source_code`) is only returned if the debug option is used.
-function template.substitute(str,env)
+-- @tparam[opt] table env the environment. This table has the following special fields:
+-- @tparam[opt=nil] table env._parent continue looking up in this table (e.g. `_parent=_G`).
+-- @tparam[opt="()"] string env._brackets bracket pair that wraps inline Lua expressions.
+-- @tparam[opt="#"] string env._escape character marking Lua lines.
+-- @tparam[opt="$"] string env._inline_escape character marking inline Lua expression.
+-- @tparam[opt="TMP"] string env._chunk_name chunk name for loaded templates, used if there
+-- is an error in Lua code.
+-- @tparam[opt=false] boolean env._debug if truthy, the generated code will be printed upon a render error.
+-- @treturn[1] string render result
+-- @treturn[1] nil
+-- @treturn[1] string source_code (only if '`env._debug`' was truthy).
+-- @treturn[2] nil
+-- @treturn[2] string error message
+-- @treturn[2] string source_code (only if '`env._debug`' was truthy).
+function template.substitute(str, env)
env = env or {}
local t, err = template.compile(str, {
- chunk_name = rawget(env,"_chunk_name"),
- escape = rawget(env,"_escape"),
- inline_escape = rawget(env,"_inline_escape"),
- inline_brackets = rawget(env,"_brackets"),
- newline = nil,
- debug = rawget(env,"_debug")
+ chunk_name = rawget(env, "_chunk_name"),
+ escape = rawget(env, "_escape"),
+ inline_escape = rawget(env, "_inline_escape"),
+ inline_brackets = rawget(env, "_brackets"),
+ newline = false,
+ debug = rawget(env, "_debug")
})
if not t then return t, err end
- return t:render(env, rawget(env,"_parent"), rawget(env,"_debug"))
+ return t:render(env, rawget(env, "_parent"), rawget(env, "_debug"))
end
--- executes the previously compiled template and renders it.
@@ -12894,12 +12973,16 @@ end
-- @tab[opt] parent continue looking up in this table (e.g. `parent=_G`).
-- @bool[opt] db if thruthy, it will print the code upon a render error
-- (provided the template was compiled with the debug option).
--- @return `rendered template + nil + source_code`, or `nil + error + source_code`. The last return value
--- (`source_code`) is only returned if the template was compiled with the debug option.
+-- @treturn[1] string render result
+-- @treturn[1] nil
+-- @treturn[1] string source_code (only if '`env._debug`' was truthy).
+-- @treturn[2] nil
+-- @treturn[2] string error message
+-- @treturn[2] string source_code (only if '`env._debug`' was truthy).
-- @usage
-- local ct, err = template.compile(my_template)
-- local rendered , err = ct:render(my_env, parent)
-local render = function(self, env, parent, db)
+local function render(self, env, parent, db)
env = env or {}
if parent then -- parent is a bit silly, but for backward compatibility retained
setmetatable(env, {__index = parent})
@@ -12911,25 +12994,27 @@ local render = function(self, env, parent, db)
if self.code and db then print(self.code) end
return nil, out, self.code
end
- return table.concat(out), nil, self.code
+ return concat(out), nil, self.code
end
--- compiles the template.
-- Returns an object that can repeatedly be rendered without parsing/compiling
--- the template again.
--- The options passed in the `opts` table support the following options:
---
--- * `chunk_name`: chunk name for loaded templates, used if there
--- is an error in Lua code. Default is 'TMP'.
--- * `escape`: character marking Lua lines, default is '#'
--- * `inline_escape`: character marking inline Lua expression, default is '$'.
--- * `inline_brackets`: bracket pair that wraps inline Lua expressions, default is '()'.
--- * `newline`: string to replace newline characters, default is `nil` (not replacing newlines).
--- * `debug`: if truthy, the generated source code will be retained within the compiled template object, default is `nil`.
---
--- @string str the template string
--- @tab[opt] opts the compilation options to use
--- @return template object, or `nil + error + source_code`
+-- the template again. Preserves the line layout of the template so that line
+-- numbers in error messages should point to the correct lines in the source
+-- string.
+-- @tparam string str the template string
+-- @tparam[opt] table opts the compilation options to use. This table supports the following options:
+-- @tparam[opt="TMP"] string opts.chunk_name chunk name for loaded templates, used if there
+-- is an error in Lua code.
+-- @tparam[opt="#"] string opts.escape character marking Lua lines.
+-- @tparam[opt="$"] string opts.inline_escape character marking inline Lua expression.
+-- @tparam[opt="()"] string opts.inline_brackets bracket pair that wraps inline Lua expressions.
+-- @tparam[opt=false] boolean opts.newline if truthy, newlines will be stripped from text in the template.
+-- @tparam[opt=false] boolean opts.debug if truthy, the generated code will be printed upon a render error.
+-- @treturn[1] ct compiled template object
+-- @treturn[2] nil
+-- @treturn[2] string error message
+-- @treturn[2] string source_code
-- @usage
-- local ct, err = template.compile(my_template)
-- local rendered , err = ct:render(my_env, parent)
@@ -12940,9 +13025,9 @@ function template.compile(str, opts)
local inline_escape = opts.inline_escape or '$'
local inline_brackets = opts.inline_brackets or '()'
- local code, short = parseHashLines(str,inline_escape,inline_brackets,escape,opts.newline)
+ local code, short = parseHashLines(str, inline_escape, inline_brackets, escape, opts.newline)
local env = { __tostring = tostring }
- local fn, err = utils.load(code, chunk_name,'t',env)
+ local fn, err = utils.load(code, chunk_name, 't', env)
if not fn then return nil, err, code end
if short then
@@ -13453,7 +13538,8 @@ local operators
local _function_factories = {}
-local utils = { _VERSION = "1.13.1" }
+local utils = { _VERSION = "1.14.0" }
+
for k, v in pairs(compat) do utils[k] = v end
--- Some standard patterns
@@ -13571,7 +13657,11 @@ end
-- @param value1 Value returned if cond is truthy
-- @param value2 Value returned if cond is falsy
function utils.choose(cond, value1, value2)
- return cond and value1 or value2
+ if cond then
+ return value1
+ else
+ return value2
+ end
end
--- convert an array of values to strings.
@@ -13727,7 +13817,7 @@ end
-- non-existing values, and/or converting strings/identifiers to other values.
--
-- Calling on the object does the same, but returns a soft error; `nil + err`, if
--- the call is succesful (the key exists), it will return the value.
+-- the call is successful (the key exists), it will return the value.
--
-- When calling with varargs or an array the values will be equal to the keys.
-- The enum object is read-only.
@@ -13755,7 +13845,7 @@ end
-- },
--
-- some_method = function(self)
--- return self.ERR.OUT_OF_BOUNDS
+-- return nil, self.ERR.OUT_OF_BOUNDS
-- end,
-- }
--
@@ -14011,6 +14101,11 @@ end
--- OS functions
-- @section OS-functions
+--- Execute a shell command.
+-- This function is a copy of `compat.execute`.
+-- @class function
+-- @name utils.execute
+
--- execute a shell command and return the output.
-- This function redirects the output to tempfiles and returns the content of those files.
-- @param cmd a shell command
@@ -14121,7 +14216,7 @@ end
-- @param s The input string
-- @param re optional A Lua string pattern; defaults to '%s+'
-- @param plain optional If truthy don't use Lua patterns
--- @param n optional maximum number of elements (if there are more, the last will remian un-split)
+-- @param n optional maximum number of elements (if there are more, the last will remain un-split)
-- @return a list-like table
-- @raise error if s is not a string
-- @see splitv
@@ -14175,8 +14270,8 @@ end
-- This is useful if you have a function which is relatively expensive,
-- but you don't know in advance what values will be required, so
-- building a table upfront is wasteful/impossible.
--- @param func a function of at least one argument
--- @return a function with at least one argument, which is used as the key.
+-- @param func a function that takes exactly one argument (which later serves as the cache key) and returns a single value
+-- @return a function taking one argument and returning a single value either from the cache or by running the original input function
function utils.memoize(func)
local cache = {}
return function(k)
diff --git a/Master/texmf-dist/tex/luatex/penlight/penlight.sty b/Master/texmf-dist/tex/luatex/penlight/penlight.sty
index 7a7c94b6a77..8a0bb2c8f00 100644
--- a/Master/texmf-dist/tex/luatex/penlight/penlight.sty
+++ b/Master/texmf-dist/tex/luatex/penlight/penlight.sty
@@ -1,6 +1,6 @@
% Kale Ewasiuk (kalekje@gmail.com)
-% 2023-07-22
-% Copyright (C) 2021-2023 Kale Ewasiuk
+% 2024-09-15
+% Copyright (C) 2021-2024 Kale Ewasiuk
%
% Permission is hereby granted, free of charge, to any person obtaining a copy
% of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,7 @@
% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
% OR OTHER DEALINGS IN THE SOFTWARE.
-\ProvidesPackage{penlight}[2023-07-22]
+\ProvidesPackage{penlight}[2024-09-15]
\directlua{penlight = require'penlight'}
diff --git a/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.lua b/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.lua
index e51b01c14bd..0e948c3fe18 100644
--- a/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.lua
+++ b/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.lua
@@ -1,5 +1,5 @@
--% Kale Ewasiuk (kalekje@gmail.com)
---% 2024-03-14
+--% 2024-08-17
--% Copyright (C) 2021-2024 Kale Ewasiuk
--%
--% Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -857,6 +857,21 @@ end
+function penlight.caseswitch(s, c, kv)
+ local kvtbl = penlight.luakeys.parse(kv)
+ local sw = kvtbl[c] -- the returned switch
+ if sw == nil then -- if switch not found
+ if s == penlight.tex.xTrue then -- if star, throw error
+ pl.tex.pkgerror('penlight', 'case: "'..c..'" not found in key-vals: "'..kv..'"')
+ sw = ''
+ else
+ sw = kvtbl['__'] or '' -- use __ as not found case
+ end
+ end
+ tex.sprint(sw)
+end
+
+
penlight.tbls = {}
diff --git a/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.sty b/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.sty
index 3c411d227ac..58580036b5b 100644
--- a/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.sty
+++ b/Master/texmf-dist/tex/luatex/penlightplus/penlightplus.sty
@@ -1,5 +1,5 @@
% Kale Ewasiuk (kalekje@gmail.com)
-% 2024-03-14
+% 2024-08-17
% Copyright (C) 2021-2024 Kale Ewasiuk
%
% Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -22,7 +22,7 @@
% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
% OR OTHER DEALINGS IN THE SOFTWARE.
-\ProvidesPackage{penlightplus}[2024-03-14]
+\ProvidesPackage{penlightplus}[2024-08-17]
\RequirePackage{luacode}
\RequirePackage{luakeys}
@@ -97,6 +97,18 @@
+
+
+
+\NewDocumentCommand{\caseswitch}{s m +m}{\ignorespaces\luadirect{penlight.caseswitch(\luastring{#1},\luastring{#2},\luastringN{#3})}\unskip}
+% argument 1 is star option, which throws an error if case is not found
+% argument 2 is the case, fully expanded
+% argument 3 is a luakeys table of options, not expanded
+
+
+
+
+
%%% tbls below
\NewDocumentCommand{\tblnew}{m}{\luadirect{% initialize a tbl and set blank