Compare commits

...

4 Commits

Author SHA1 Message Date
Marcel Fabian Krüger
23c6714e97 align support and fixes 2021-04-24 16:53:50 +02:00
Marcel Fabian Krüger
c0a1f60962 Better embellished operator handling 2021-04-23 07:50:21 +02:00
Marcel Fabian Krüger
d6bda3aff3 Reorganize and add missing file 2021-04-23 02:59:35 +02:00
Marcel Fabian Krüger
8be2760919 Don't require unicode-math 2021-04-22 23:38:28 +02:00
12 changed files with 466 additions and 103 deletions

84
luamml-amsmath.lua Normal file
View File

@ -0,0 +1,84 @@
local write_xml = require'luamml-xmlwriter'
local make_root = require'luamml-convert'.make_root
local properties = node.get_properties_table()
local funcid = luatexbase.new_luafunction'luamml_amsmath_add_box_to_row:'
token.set_lua('luamml_amsmath_add_box_to_row:', funcid, 'protected')
lua.get_functions_table()[funcid] = function()
-- TODO: Error handling etc
-- local box = token.scan_int()
local boxnum = 0
local startmath = tex.box[boxnum].list
assert(startmath.id == node.id"math")
local props = assert(properties[startmath])
local mml = assert(props.saved_mathml_table)
table.insert(mml, 1, {[0] = 'maligngroup'})
if mml[0] == 'mstyle' and mml.displaystyle == true then
mml[0], mml.displaystyle, mml.scriptlevel = 'mtd', nil, nil
else
if mml[0] ~= 'mstyle' then
mml = {[0] = 'mstyle', displaystyle = false, mml}
end
mml = {[0] = 'mtd', mml}
end
local row_temp = tex.nest[tex.nest.ptr-1]
print(row_temp)
props = properties[row_temp]
if not props then
props = {}
properties[row_temp] = props
end
if not props.mathml_row then
props.mathml_row = {[0] = 'mtr'}
end
mml_row = props.mathml_row
table.insert(mml_row, mml)
end
local funcid = luatexbase.new_luafunction'luamml_amsmath_finalize_row:'
token.set_lua('luamml_amsmath_finalize_row:', funcid, 'protected')
lua.get_functions_table()[funcid] = function()
-- TODO: Error handling etc
local row_temp = tex.nest[tex.nest.ptr-1]
print("final", row_temp)
local props = properties[row_temp]
if not props then return end
if not props.mathml_row then return end
mml_row = props.mathml_row
props = properties[tex.lists.align_head]
if not props then
props = {}
properties[tex.lists.align_head] = props
end
local mml_table = props.mathml_table_node_table
if not mml_table then
mml_table = {[0] = 'mtable', displaystyle = true}
props.mathml_table_node_table = mml_table
end
table.insert(mml_table, mml_row)
end
local funcid = luatexbase.new_luafunction'luamml_amsmath_finalize_table:'
token.set_lua('luamml_amsmath_finalize_table:', funcid)
lua.get_functions_table()[funcid] = function()
-- TODO: Error handling etc
local props = properties[tex.lists.align_head]
if not props then return end
local mml_table = props.mathml_table_node_table
if not mml_table then return end
print(write_xml(make_root(mml_table, 2)))
end
funcid = luatexbase.new_luafunction'luamml_last_math_alignmark:'
token.set_lua('luamml_last_math_alignmark:', funcid, 'protected')
lua.get_functions_table()[funcid] = function()
local n = tex.nest.top.tail
n = n.nucleus or n
local props = properties[n]
if not props then
props = {}
properties[n] = props
end
props.mathml_table = {[0] = 'malignmark'}
end

View File

@ -1,5 +1,5 @@
local remap_comb = require'remap_comb'
local stretchy = require'stretchy'
local remap_comb = require'luamml-data-combining'
local stretchy = require'luamml-data-stretchy'
local properties = node.get_properties_table()
@ -14,18 +14,38 @@ local noad_sub = node.subtypes'noad'
local radical_sub = node.subtypes'radical'
local fence_sub = node.subtypes'fence'
local remap_lookup = setmetatable({}, {__index = function(t, k)
local ch = utf8.char(k & 0x1FFFFF)
t[k] = ch
return ch
end})
local digit_map = {["0"] = true, ["1"] = true,
["2"] = true, ["3"] = true, ["4"] = true,
["5"] = true, ["6"] = true, ["7"] = true,
["8"] = true, ["9"] = true,}
-- Two marker tables. They are used instead of an embellished operator to mark space-like or user provided constructs
local user_provided, space_like = {}, {}
local nodes_to_table
local function sub_style(s) return s//4*2+5 end
local function sup_style(s) return s//4*2+4+s%2 end
-- The _to_table functions generally return a second argument which is
-- could be (if it were a <mo>) a core operator of the embellishe operator
-- or space_like/user_provided
-- The delim_to_table and acc_to_table are special since their return value should
-- always be considered a core operator
-- We ignore large_... since they aren't used for modern fonts
local function delim_to_table(delim)
if not delim then return end
local props = properties[delim] props = props and props.mathml_table
if props then return props end
local fam = delim.small_fam
return {[0] = 'mo', utf8.char(delim.small_char), ['tex:family'] = fam ~= 0 and fam or nil, stretchy = not stretchy[delim.small_char] or nil }
local char = remap_lookup[fam << 21 | delim.small_char]
return {[0] = 'mo', char, ['tex:family'] = fam ~= 0 and fam or nil, stretchy = not stretchy[char] or nil }
end
-- Like kernel_to_table but always a math_char_t. Also creating a mo and potentially remapping to handle combining chars
@ -36,9 +56,9 @@ local function acc_to_table(acc, cur_style, stretch)
if acc.id ~= math_char_t then
error'confusion'
end
local char = utf8.char(acc.char)
char = remap_comb[char] or char
local fam = acc.fam
local char = remap_lookup[fam << 21 | acc.char]
char = remap_comb[char] or char
if stretch ~= not stretchy[char] then -- Handle nil gracefully in stretchy
stretch = nil
end
@ -48,15 +68,21 @@ end
local function kernel_to_table(kernel, cur_style)
if not kernel then return end
local props = properties[kernel] props = props and props.mathml_table
if props then return props end
if props then return props, user_provided end
local id = kernel.id
if id == math_char_t then
local char = kernel.char
local elem = char >= 0x30 and char < 0x39 and 'mn' or 'mi'
local fam = kernel.fam
return {[0] = elem, utf8.char(char), ['tex:family'] = fam ~= 0 and fam or nil, mathvariant = char < 0x10000 and 'normal' or nil }
local char = remap_lookup[fam << 21 | kernel.char]
local elem = digit_map[char] and 'mn' or 'mi'
local result = {[0] = elem,
char,
['tex:family'] = fam ~= 0 and fam or nil,
mathvariant = #char == 1 and elem == 'mi' and utf8.codepoint(char) < 0x10000 and 'normal' or nil
}
return result, result
elseif id == sub_box_t then
return {[0] = 'mi', {[0] = 'mglyph', ['tex:box'] = kernel.list}}
local result = {[0] = 'mi', {[0] = 'mglyph', ['tex:box'] = kernel.list}}
return result, result
elseif id == sub_mlist_t then
return nodes_to_table(kernel.list, cur_style)
else
@ -64,34 +90,34 @@ local function kernel_to_table(kernel, cur_style)
end
end
local function do_sub_sup(t, n, cur_style)
local function do_sub_sup(t, core, n, cur_style)
local sub = kernel_to_table(n.sub, sub_style(cur_style))
local sup = kernel_to_table(n.sup, sup_style(cur_style))
if sub then
if sup then
return {[0] = 'msubsup', t, sub, sup}
return {[0] = 'msubsup', t, sub, sup}, core
else
return {[0] = 'msub', t, sub}
return {[0] = 'msub', t, sub}, core
end
elseif sup then
return {[0] = 'msup', t, sup}
return {[0] = 'msup', t, sup}, core
else
return t
return t, core
end
end
local function noad_to_table(noad, sub, cur_style)
local class = noad_sub[sub]
local nucleus = kernel_to_table(noad.nucleus, class == 'over' and cur_style//2*2+1 or cur_style)
local nucleus, core = kernel_to_table(noad.nucleus, class == 'over' and cur_style//2*2+1 or cur_style)
if class == 'ord' then
elseif class == 'opdisplaylimits' or class == 'oplimits' or class == 'opnolimits' or class == 'bin' or class == 'rel' or class == 'open'
or class == 'close' or class == 'punct' or class == 'inner' then
if nucleus[0] == 'mrow' then
if not core or not core[0] then
-- TODO
else
nucleus[0] = 'mo'
if stretchy[nucleus[1]] then nucleus.stretchy = false end
if nucleus.mathvariant == 'normal' then nucleus.mathvariant = nil end
core[0] = 'mo'
if stretchy[core[1]] then core.stretchy = false end
if core.mathvariant == 'normal' then core.mathvariant = nil end
end
nucleus['tex:class'] = class
@ -103,35 +129,35 @@ local function noad_to_table(noad, sub, cur_style)
nucleus,
sub or sup,
sub and sup,
}
}, core
end
elseif class == 'under' then
return {[0] = 'munder',
nucleus,
{[0] = 'mo', '_',},
}
}, core
elseif class == 'over' then
return {[0] = 'mover',
nucleus,
{[0] = 'mo', '\u{203E}',},
}
}, core
elseif class == 'vcenter' then
nucleus['tex:TODO'] = class
else
error[[confusion]]
end
return do_sub_sup(nucleus, noad, cur_style)
return do_sub_sup(nucleus, core, noad, cur_style)
end
local function accent_to_table(accent, sub, cur_style)
local nucleus = kernel_to_table(accent.nucleus, cur_style//2*2+1)
local nucleus, core = kernel_to_table(accent.nucleus, cur_style//2*2+1)
local top_acc = acc_to_table(accent.accent, cur_style, sub & 1 == 1)
local bot_acc = acc_to_table(accent.bot_accent, cur_style, sub & 2 == 2)
return {[0] = top_acc and (bot_acc and 'munderover' or 'mover') or 'munder',
nucleus,
bot_acc or top_acc,
bot_acc and top_acc,
}
}, core
end
local style_table = {
@ -148,19 +174,19 @@ style_table.crampedscript, style_table.crampedscriptscript =
local function radical_to_table(radical, sub, cur_style)
local kind = radical_sub[sub]
local nucleus = kernel_to_table(radical.nucleus, cur_style//2*2+1)
local nucleus, core = kernel_to_table(radical.nucleus, cur_style//2*2+1)
local left = delim_to_table(radical.left)
local elem
if kind == 'radical' or kind == 'uradical' then
-- FIXME: Check that this is really a square root
elem = {[0] = 'msqrt', nucleus}
elem, core = {[0] = 'msqrt', nucleus}, nil
elseif kind == 'uroot' then
-- FIXME: Check that this is really a root
elem = {[0] = 'msqrt', nucleus, kernel_to_table(radical.degree)}
elem, core = {[0] = 'msqrt', nucleus, kernel_to_table(radical.degree)}, nil
elseif kind == 'uunderdelimiter' then
elem = {[0] = 'munder', left, nucleus}
elem, core = {[0] = 'munder', left, nucleus}, left
elseif kind == 'uoverdelimiter' then
elem = {[0] = 'mover', left, nucleus}
elem, core = {[0] = 'mover', left, nucleus}, left
elseif kind == 'udelimiterunder' then
elem = {[0] = 'munder', nucleus, left}
elseif kind == 'udelimiterover' then
@ -168,11 +194,11 @@ local function radical_to_table(radical, sub, cur_style)
else
error[[confusion]]
end
return do_sub_sup(elem, radical, cur_style)
return do_sub_sup(elem, core, radical, cur_style)
end
local function fraction_to_table(fraction, sub, cur_style)
local num = kernel_to_table(fraction.num, sup_style(cur_style))
local num, core = kernel_to_table(fraction.num, sup_style(cur_style))
local denom = kernel_to_table(fraction.denom, sub_style(cur_style))
local left = delim_to_table(fraction.left)
local right = delim_to_table(fraction.right)
@ -194,23 +220,24 @@ local function fraction_to_table(fraction, sub, cur_style)
right,
}
else
return mfrac
return mfrac, core
end
end
local function fence_to_table(fence, sub, cur_style)
local delim = delim_to_table(fence.delimiter)
delim.fence = 'true'
return delim
return delim, delim
end
local function space_to_table(amount, sub, cur_style)
if amount == 0 then return end
-- FIXME: What does MathML do in subscripts etc.? Probably we have to "unscale" in the non mu case...
if sub == 99 then -- TODO magic number
return {[0] = 'mspace', width = string.format("%.2fem", amount/18)}
-- 18*2^16=1179648
return {[0] = 'mspace', width = string.format("%.2fem", amount/1179648)}, space_like
else
return {[0] = 'mspace', width = string.format("%.2fem", amount/tex.sp'1em')}
-- 65781.76=tex.sp'100bp'/100
return {[0] = 'mspace', width = string.format("%.2fpt", amount/65781.76)}, space_like
end
end
@ -218,16 +245,21 @@ function nodes_to_table(head, cur_style)
local t = {[0] = "mrow"}
local result = t
local nonscript
local core = space_like
for n, id, sub in node.traverse(head) do
local new_core
local props = properties[n] props = props and props.mathml_table
if props then
t[#t+1] = props
t[#t+1], new_core = props, user_provided
elseif id == noad_t then
t[#t+1] = noad_to_table(n, sub, cur_style)
t[#t+1], new_core = noad_to_table(n, sub, cur_style)
elseif id == accent_t then
t[#t+1] = accent_to_table(n, sub, cur_style)
t[#t+1], new_core = accent_to_table(n, sub, cur_style)
elseif id == style_t then
if #t ~= 0 then
if sub ~= cur_style then
if #t == 0 then
t[0] = 'mstyle'
else
local new_t = {[0] = 'mstyle'}
t[#t+1] = new_t
t = new_t
@ -238,44 +270,68 @@ function nodes_to_table(head, cur_style)
t.displaystyle, t.scriptlevel = false, sub//2 - 1
end
cur_style = sub
end
new_core = space_like
elseif id == choice_t then
local size = cur_style//2
t[#t+1] = nodes_to_table(n[size == 0 and 'display' or size == 1 and 'text'
t[#t+1], new_core = nodes_to_table(n[size == 0 and 'display'
or size == 1 and 'text'
or size == 2 and 'script'
or size == 3 and 'scriptscript' or assert(false)], 2*size)
or size == 3 and 'scriptscript'
or assert(false)], 2*size), space_like
elseif id == radical_t then
t[#t+1] = radical_to_table(n, sub, cur_style)
t[#t+1], new_core = radical_to_table(n, sub, cur_style)
elseif id == fraction_t then
t[#t+1] = fraction_to_table(n, sub, cur_style)
t[#t+1], new_core = fraction_to_table(n, sub, cur_style)
elseif id == fence_t then
t[#t+1] = fence_to_table(n, sub, cur_style)
t[#t+1], new_core = fence_to_table(n, sub, cur_style)
elseif id == kern_t then
if not nonscript then
t[#t+1] = space_to_table(n.kern, sub, cur_style)
t[#t+1], new_core = space_to_table(n.kern, sub, cur_style)
end
elseif id == glue_t then
if cur_style >= 4 or not nonscript then
if sub == 98 then -- TODO magic number
nonscript = true
else
t[#t+1] = space_to_table(n.width, sub, cur_style)
t[#t+1], new_core = space_to_table(n.width, sub, cur_style)
end
end
else
t[#t+1] = {[0] = 'tex:TODO', other = n}
new_core = {[0] = 'tex:TODO', other = n}
t[#t+1] = new_core
end
nonscript = nil
if core and new_core ~= space_like then
core = new_core
end
return result
end
return result, core
end
return function(head, style)
local result = nodes_to_table(head, style or 0)
result[0] = 'math'
result.xmlns = 'http://www.w3.org/1998/Math/MathML'
result['xmlns:tex'] = 'http://typesetting.eu/2021/LuaMathML'
if style == 2 then
result.display = 'block'
local function register_remap(family, mapping)
family = family << 21
for from, to in next, mapping do
remap_lookup[family | from] = utf8.char(to)
end
return result
end
local function to_math(root, style)
if root[0] == 'mrow' then
root[0] = 'math'
else
root = {[0] = 'math', root}
end
root.xmlns = 'http://www.w3.org/1998/Math/MathML'
root['xmlns:tex'] = 'http://typesetting.eu/2021/LuaMathML'
if style < 2 then
root.display = 'block'
end
return root
end
return {
register_family = register_remap,
process = function(head, style) return nodes_to_table(head, style or 2) end,
make_root = to_math,
}

View File

@ -0,0 +1,51 @@
-- local remap_ot1 = {
-- 0x0393, 0x0394, 0x0398, 0x039B, 0x039E, 0x03A0, 0x03A3, 0x03A5,
-- 0x03A6, 0x03A8, 0x03A9, nil, nil, nil, nil, nil,
-- }
local remap_oml = { [0] =
-- Greek italic
0x1D6E4, 0x1D6E5, 0x1D6E9, 0x1D6EC, 0x1D6EF, 0x1D6F1, 0x1D6F4, 0x1D6F6,
0x1D6F7, 0x1D6F9, 0x1D6FA, 0x1D6FC, 0x1D6FD, 0x1D6FE, 0x1D6FF, 0x1D716,
0x1D701, 0x1D702, 0x1D703, 0x1D704, 0x1D705, 0x1D706, 0x1D707, 0x1D708,
0x1D709, 0x1D70B, 0x1D70C, 0x1D70E, 0x1D70F, 0x1D710, 0x1D719, 0x1D712,
0x1D713, 0x1D714, 0x1D700, 0x1D717, 0x1D71B, 0x1D71A, 0x1D70D, 0x1D711,
-- Symbols. (The nils are hook parts)
0x21BC, 0x21BD, 0x21C0, 0x21C1, nil, nil, 0x22BB, 0x22BC,
-- old style numerals (nobody should ever use these in math) and some punctuation
nil, nil, nil, nil, nil, nil, nil, nil,
nil, nil, 0x2E, 0x2C, 0x3C, 0x2F, 0x3E, 0x226D,
-- letters filled up with symbols
0x2202, 0x1D434, 0x1D435, 0x1D436, 0x1D437, 0x1D438, 0x1D439, 0x1D43A,
0x1D43B, 0x1D43C, 0x1D43D, 0x1D43E, 0x1D43F, 0x1D440, 0x1D441, 0x1D442,
0x1D443, 0x1D444, 0x1D445, 0x1D446, 0x1D447, 0x1D448, 0x1D449, 0x1D44A,
0x1D44B, 0x1D44C, 0x1D44D, 0x266D, 0x266E, 0x266F, 0x2323, 0x2322,
0x2113, 0x1D44E, 0x1D44F, 0x1D450, 0x1D451, 0x1D452, 0x1D453, 0x1D454,
0x210E, 0x1D456, 0x1D457, 0x1D458, 0x1D459, 0x1D45A, 0x1D45B, 0x1D45C,
0x1D45D, 0x1D45E, 0x1D45F, 0x1D460, 0x1D461, 0x1D462, 0x1D463, 0x1D464,
0x1D465, 0x1D466, 0x1D467, 0x1D6A4, 0x1D6A5, 0x2118, 0x2192, nil,
}
local remap_oms = { [0] =
0x2212, 0x22C5, 0xD7, 0x2A, 0xF7, 0x22C4, 0xB1, 0x2213,
0x2295, 0x2296, 0x2297, 0x2298, 0x2299, 0x25CB, 0x2218, 0x2219,
0x224D, 0x2261, 0x2286, 0x2287, 0x2264, 0x2265, 0x2AAF, 0x2AB0,
0x223C, 0x2248, 0x2282, 0x2283, 0x226A, 0x226B, 0x227A, 0x227B,
0x2190, 0x2192, 0x2191, 0x2193, 0x2194, 0x2197, 0x2198, 0x2243,
0x21D0, 0x21D2, 0x21D1, 0x21D3, 0x21D4, 0x2196, 0x2199, 0x221D,
0x2032, 0x221E, 0x2208, 0x220B, 0x25B3, 0x25BD, 0x0338, 0x21A6,
0x2200, 0x2203, 0xAC, 0x2205, 0x211C, 0x22A9, 0x22A4, 0x22A5,
0x2135, 0x1D49C, 0x212C, 0x1D49E, 0x1D49F, 0x2130, 0x2131, 0x1D4A2,
0x210B, 0x2110, 0x1D4A5, 0x1D4A6, 0x2112, 0x2133, 0x1D4A9, 0x1D4AA,
0x1D4AB, 0x1D4AC, 0x211B, 0x1D4AE, 0x1D4AF, 0x1D4B0, 0x1D4B1, 0x1D4B2,
0x1D4B3, 0x1D4B4, 0x1D4B5, 0x222A, 0x2229, 0x228E, 0x2227, 0x2228,
0x22A2, 0x22A3, 0x230A, 0x230B, 0x2308, 0x2309, 0x7B, 0x7D,
0x27E8, 0x27E9, 0x7C, 0x2016, 0x2195, 0x21D5, 0x5C, 0x2240,
0x221A, 0x2210, 0x2207, 0x222B, 0x2294, 0x2293, 0x2291, 0x2292,
0xA7, 0x2020, 0x2021, 0xB6, 0x2663, 0x2662, 0x2661, 0x2660,
}
return {
oml = remap_oml,
oms = remap_oms,
}

View File

@ -0,0 +1,99 @@
\ProvidesExplPackage {luamml-patches-amsmath} {2021-04-23} {0.0.1-alpha}
{Feel free to add a description here}
\lua_now:n { require'luamml-amsmath' }
\cs_set:Npn \align@preamble {
&
\hfil
\strut@
\setboxz@h {
\@lign
$
\m@th
\displaystyle {
##
}
\ifmeasuring@
\luamml_flag_ignore:
\else
\luamml_flag_alignment_left:
\fi
$
}
\ifmeasuring@
\savefieldlength@
\fi
\set@field
\tabskip\z@skip
&
\setboxz@h {
\@lign
$
\m@th
\displaystyle
{
{}
\luamml_last_math_alignmark:
##
}
\ifmeasuring@
\luamml_flag_ignore:
\else
\luamml_flag_alignment_right:
\fi
$
}
\ifmeasuring@
\savefieldlength@
\else
\luamml_amsmath_add_box_to_row:
\fi
\set@field
\hfil
\tabskip\alignsep@
}
\cs_set:Npn \math@cr@@@align {
\ifst@rred
\nonumber
\fi
\if@eqnsw
\global \tag@true
\fi
\global \advance \row@ \@ne
\add@amps \maxfields@
\omit
\kern -\alignsep@
\luamml_amsmath_finalize_row:
\iftag@
\setboxz@h {
\@lign
\strut@
{ \make@display@tag }
}
\place@tag
\fi
\ifst@rred
\else
\global \@eqnswtrue
\fi
\global \lineht@ \z@
\cr
}
\cs_set:Npn \endalign {
\math@cr
\black@ \totwidth@
\luamml_amsmath_finalize_table:
\egroup
\ifingather@
\restorealignstate@
\egroup
\nonumber
\ifnum0={\fi\iffalse}\fi
\else
$$
\fi
\ignorespacesafterend
}

75
luamml-tex.lua Normal file
View File

@ -0,0 +1,75 @@
local mlist_to_mml = require'luamml-convert'
local process_mlist = mlist_to_mml.process
local make_root = mlist_to_mml.make_root
local register_family = mlist_to_mml.register_family
local mappings = require'luamml-legacy-mappings'
local write_xml = require'luamml-xmlwriter'
local properties = node.get_properties_table()
local funcid = luatexbase.new_luafunction'RegisterFamilyMapping'
token.set_lua('RegisterFamilyMapping', funcid, 'protected')
lua.get_functions_table()[funcid] = function()
local fam = token.scan_int()
local mapping = token.scan_string()
if mappings[mapping] then
register_family(fam, mappings[mapping])
else
tex.error(string.format('Unknown font mapping %q', mapping))
end
end
-- Possible flag values:
-- 0: Normal (This is the only supported one in display mode)
-- 1: Like 0, result is display math
-- 2: Generate MathML, but only save it for later usage in startmath node
-- 3: Skip
-- 4: Prepend node list from buffer before generating
-- 5: Like 5, result is display math
-- 6: 2+4
-- 7: Skip but save copy of node list in buffer
--
-- In other words:
-- Bit 1: Suppress output
-- Bit 0: Force display if 1 isn't set, if it is then skip MathML generation
-- Bit 2: Integrate with table mechanism
local mlist_buffer
luatexbase.add_to_callback('pre_mlist_to_hlist_filter', function(mlist, style)
local flag = tex.count.l__luamml_flag_int
if flag & 3 == 3 then
if flag & 4 == 4 then
assert(mlist_buffer == nil)
mlist_buffer = node.copy_list(mlist)
end
return true
end
local new_mlist, buffer_tail
if flag & 4 == 4 then
new_mlist, buffer_tail = assert(mlist_buffer), node.tail(mlist_buffer)
mlist.prev, buffer_tail.next = buffer_tail, mlist
mlist_buffer = nil
else
new_mlist = mlist
end
local xml = process_mlist(new_mlist, style == 'display' and 0 or 2)
if flag & 2 == 0 then
print(write_xml(make_root(xml, (style == 'display' or flag & 1 == 1) and 0 or 2)) .. '\n')
else
assert(style == 'text')
local startmath = tex.nest.top.tail
local props = properties[startmath]
if not props then
props = {}
properties[startmath] = props
end
props.saved_mathml_table = xml
end
if buffer_tail then
mlist.prev, buffer_tail.next = nil, nil
node.flush_list(new_mlist)
end
return true
end, 'dump_list')

View File

@ -3,7 +3,6 @@ local function escape_name(name)
return name
end
-- FIXME: Not sure yet if this will be needed
local escapes = {
['"'] = "&quot;",
['<'] = "&lt;",
@ -41,4 +40,7 @@ local function write_elem(tree, indent)
return out .. '</' .. escaped_name .. '>'
end
return write_elem
return function(element, indent, version)
return (version == '11' and '<?xml version="1.1"?>' or '') ..
write_elem(element, indent and '' or nil)
end

17
luamml.sty Normal file
View File

@ -0,0 +1,17 @@
\ProvidesExplPackage {luamml} {2021-04-23} {0.0.1-alpha}
{Feel free to add a description here}
\int_new:N \l__luamml_flag_int
\lua_now:n { require'luamml-tex' }
\cs_new:Nn \luamml_flag_ignore: {
\int_set:Nn \l__luamml_flag_int { 3 }
}
\cs_new:Nn \luamml_flag_alignment_left: {
\int_set:Nn \l__luamml_flag_int { 7 }
}
\cs_new:Nn \luamml_flag_alignment_right: {
\int_set:Nn \l__luamml_flag_int { 6 }
}
\RequirePackage { luamml-patches-amsmath }

View File

@ -1,14 +0,0 @@
local inspect = require'inspect'
local function show(t) return print(inspect(t)) end
local mlist_to_table = require'mlist_to_mml'
local write_xml = require'write_xml'
luatexbase.add_to_callback('pre_mlist_to_hlist_filter', function(mlist, style)
print'\n\n'
local xml = mlist_to_table(mlist, style == 'display' and 2 or 0)
print(write_xml(xml))
-- print(write_xml(xml, '\n'))
print'\n'
return true
end, 'dump_list')

View File

@ -1,9 +1,12 @@
\documentclass{article}
\usepackage{unicode-math}
\directlua{require'test_tex'}
\usepackage{amsmath}
\usepackage{luamml}
\RegisterFamilyMapping\symsymbols{oms}
\RegisterFamilyMapping\symletters{oml}
\begin{document}
\[
ax^2+b+c=0
ax^2+bx+c=0
\]
\[
x = \frac{-b \pm \sqrt{b^2-4ac}}{2a}.
@ -12,5 +15,11 @@
\sum_a\underline c\dot bc'
\]
\begin{align}
abc&=def\\
1+2&=3\\
5
\end{align}
Es gilt $\sin(x)-\sin(x+2\pi)=0$.
\end{document}

View File

@ -1,16 +0,0 @@
local write_xml = require'write_xml'
print(write_xml{[0] = "math", xmlns = "http://www.w3.org/1998/Math/MathML",
{[0] = "mi", "a"},
{[0] = "msup",
{[0] = "mi", "x"},
{[0] = "mn", "2"},
},
{[0] = "mo", "+"},
{[0] = "mi", "b"},
{[0] = "mi", "x"},
{[0] = "mo", "+"},
{[0] = "mi", "c"},
{[0] = "mo", "="},
{[0] = "mn", "0"},
})