local b = require("packages.math.base-elements")
local syms = require("packages.math.unicode-symbols")
local atomTypeShort = {
ord = b.atomType.ordinary,
big = b.atomType.bigOperator,
bin = b.atomType.binaryOperator,
rel = b.atomType.relationalOperator,
open = b.atomType.openingSymbol,
close = b.atomType.closeSymbol,
punct = b.atomType.punctuationSymbol,
inner = b.atomType.inner,
over = b.atomType.overSymbol,
under = b.atomType.underSymbol,
accent = b.atomType.accentSymbol,
radical = b.atomType.radicalSymbol,
vcenter = b.atomType.vcenter,
}
local ConvertMathML
local function convertChildren (tree)
local mboxes = {}
for _, n in ipairs(tree) do
local box = ConvertMathML(nil, n)
if box then
table.insert(mboxes, box)
end
end
return mboxes
end
function ConvertMathML (_, content)
if content == nil or content.command == nil then
return nil
end
if content.command == "math" or content.command == "mathml" then return b.stackbox("V", convertChildren(content))
elseif content.command == "mrow" then
return b.stackbox("H", convertChildren(content))
elseif content.command == "mi" then
local script = content.options.mathvariant and b.mathVariantToScriptType(content.options.mathvariant)
local text = content[1]
if type(text) ~= "string" then
SU.error("mi command contains " .. text .. ", which is not text")
end
script = script or (luautf8.len(text) == 1 and b.scriptType.italic or b.scriptType.upright)
return b.text("identifier", {}, script, text)
elseif content.command == "mo" then
local script = content.options.mathvariant and b.mathVariantToScriptType(content.options.mathvariant)
or b.scriptType.upright
local text = content[1]
local attributes = {}
if syms.symbolDefaults[text] then
for attribute, value in pairs(syms.symbolDefaults[text]) do
attributes[attribute] = value
end
end
if content.options.atom then
if not atomTypeShort[content.options.atom] then
SU.error("Unknown atom type " .. content.options.atom)
else
attributes.atom = atomTypeShort[content.options.atom]
end
end
if type(text) ~= "string" then
SU.error("mo command contains " .. text .. ", which is not text")
end
return b.text("operator", attributes, script, text)
elseif content.command == "mn" then
local script = content.options.mathvariant and b.mathVariantToScriptType(content.options.mathvariant)
or b.scriptType.upright
local text = content[1]
if type(text) ~= "string" then
SU.error("mn command contains " .. text .. ", which is not text")
end
if string.sub(text, 1, 1) == "-" then
text = "−" .. string.sub(text, 2)
end
return b.text("number", {}, script, text)
elseif content.command == "mspace" then
return b.space(content.options.width, content.options.height, content.options.depth)
elseif content.command == "msub" then
local children = convertChildren(content)
if #children ~= 2 then
SU.error("Wrong number of children in msub")
end
return b.newSubscript({ base = children[1], sub = children[2] })
elseif content.command == "msup" then
local children = convertChildren(content)
if #children ~= 2 then
SU.error("Wrong number of children in msup")
end
return b.newSubscript({ base = children[1], sup = children[2] })
elseif content.command == "msubsup" then
local children = convertChildren(content)
if #children ~= 3 then
SU.error("Wrong number of children in msubsup")
end
return b.newSubscript({ base = children[1], sub = children[2], sup = children[3] })
elseif content.command == "munder" then
local children = convertChildren(content)
if #children ~= 2 then
SU.error("Wrong number of children in munder")
end
return b.newUnderOver({ base = children[1], sub = children[2] })
elseif content.command == "mover" then
local children = convertChildren(content)
if #children ~= 2 then
SU.error("Wrong number of children in mover")
end
return b.newUnderOver({ base = children[1], sup = children[2] })
elseif content.command == "munderover" then
local children = convertChildren(content)
if #children ~= 3 then
SU.error("Wrong number of children in munderover")
end
return b.newUnderOver({ base = children[1], sub = children[2], sup = children[3] })
elseif content.command == "mfrac" then
local children = convertChildren(content)
if #children ~= 2 then
SU.error("Wrong number of children in mfrac: " .. #children)
end
return b.fraction(children[1], children[2])
elseif content.command == "mtable" or content.command == "table" then
local children = convertChildren(content)
return b.table(children, content.options)
elseif content.command == "mtr" then
return b.mtr(convertChildren(content))
elseif content.command == "mtd" then
return b.stackbox("H", convertChildren(content))
else
SU.error("Unknown math command " .. content.command)
end
end
local function handleMath (_, mbox, options)
local mode = options and options.mode or "text"
local counter = SU.boolean(options.numbered, false) and "equation"
counter = options.counter or counter
if mode == "display" then
mbox.mode = b.mathMode.display
elseif mode == "text" then
mbox.mode = b.mathMode.textCramped
else
SU.error("Unknown math mode " .. mode)
end
SU.debug("math", function ()
return "Resulting mbox: " .. tostring(mbox)
end)
mbox:styleDescendants()
mbox:shapeTree()
if mode == "display" then
SILE.typesetter:endline()
SILE.typesetter:pushExplicitVglue(SILE.settings:get("math.displayskip"))
SILE.settings:temporarily(function ()
local lskip = SILE.settings:get("document.lskip") or SILE.types.node.glue()
local rskip = SILE.settings:get("document.rskip") or SILE.types.node.glue()
SILE.settings:set("document.parindent", SILE.types.node.glue())
SILE.settings:set("current.parindent", SILE.types.node.glue())
SILE.settings:set("document.lskip", SILE.types.node.hfillglue(lskip.width.length))
SILE.settings:set("document.rskip", SILE.types.node.glue(rskip.width.length))
SILE.settings:set("typesetter.parfillskip", SILE.types.node.glue())
SILE.settings:set("document.spaceskip", SILE.types.length("1spc", 0, 0))
SILE.typesetter:pushHorizontal(mbox)
SILE.typesetter:pushExplicitGlue(SILE.types.node.hfillglue())
if counter then
options.counter = counter
SILE.call("increment-counter", { id = counter })
SILE.call("math:numberingstyle", options)
elseif options.number then
SILE.call("math:numberingstyle", options)
end
SILE.typesetter:endline()
end)
SILE.typesetter:pushExplicitVglue(SILE.settings:get("math.displayskip"))
else
SILE.typesetter:pushHorizontal(mbox)
end
end
return { ConvertMathML, handleMath }