Skip to content

Commit 4bbeaa6

Browse files
Omikhleiaalerque
authored andcommitted
fix(math): Paired open/close atoms shall be forced in a mrow in TeX-like math
So that stretching occurs on the relevant spans of content.
1 parent 0df93b1 commit 4bbeaa6

1 file changed

Lines changed: 64 additions & 7 deletions

File tree

packages/math/texlike.lua

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -260,23 +260,36 @@ local compileToStr = function (argEnv, mathlist)
260260
end
261261
end
262262

263-
local function isBigOperator (tree)
263+
local function isOperatorKind (tree, typeOfAtom, typeOfSymbol)
264+
if not tree then
265+
return false -- safeguard
266+
end
264267
if tree.command ~= "mo" then
265268
return false
266269
end
267270
-- Case \mo[atom=big]{ops}
268271
-- E.g. \mo[atom=big]{lim}
269-
if tree.options and tree.options.atom == "big" then
272+
if tree.options and tree.options.atom == typeOfAtom then
270273
return true
271274
end
272-
-- Case \mo{ops} where ops is registered as big operator (unicode-symbols)
275+
-- Case \mo{ops} where ops is registered with the resquested type
273276
-- E.g. \mo{∑) or \sum
274-
if tree[1] and symbolDefaults[tree[1]] and symbolDefaults[tree[1]].atom == atomType.bigOperator then
277+
if tree[1] and symbolDefaults[tree[1]] and symbolDefaults[tree[1]].atom == typeOfSymbol then
275278
return true
276279
end
277280
return false
278281
end
279282

283+
local function isBigOperator (tree)
284+
return isOperatorKind(tree, "big", atomType.bigOperator)
285+
end
286+
local function isCloseOperator (tree)
287+
return isOperatorKind(tree, "close", atomType.closeSymbol)
288+
end
289+
local function isOpeningOperator (tree)
290+
return isOperatorKind(tree, "open", atomType.openingSymbol)
291+
end
292+
280293
local function compileToMathML_aux (_, arg_env, tree)
281294
if type(tree) == "string" then
282295
return tree
@@ -323,12 +336,56 @@ local function compileToMathML_aux (_, arg_env, tree)
323336
-- Turn mathlist into `mrow` except if it has exactly one `mtr` or `mtd`
324337
-- child.
325338
-- Note that `def`s have already been compiled away at this point.
326-
if #tree == 1 and (tree[1].command == "mtr" or tree[1].command == "mtd") then
327-
return tree[1]
339+
if #tree == 1 then
340+
if tree[1].command == "mtr" or tree[1].command == "mtd" then
341+
return tree[1]
342+
else
343+
tree.command = "mrow"
344+
end
328345
else
346+
-- Re-wrap content from opening to closing operator in an implicit mrow,
347+
-- so stretchy operators apply to the correct span of content.
348+
local children = {}
349+
local stack = {}
350+
for _, child in ipairs(tree) do
351+
if isOpeningOperator(child) then
352+
table.insert(stack, children)
353+
local mrow = {
354+
command = "mrow",
355+
options = {},
356+
child,
357+
}
358+
table.insert(children, mrow)
359+
children = mrow
360+
elseif isCloseOperator(child) then
361+
table.insert(children, child)
362+
if #stack > 0 then
363+
children = table.remove(stack)
364+
end
365+
elseif
366+
(child.command == "msubsup" or child.command == "msub" or child.command == "msup")
367+
and isCloseOperator(child[1]) -- child[1] is the base
368+
then
369+
if #stack > 0 then
370+
-- Special case for closing operator with sub/superscript:
371+
-- (....)^i must be interpreted as {(....)}^i, not as (...{)}^i
372+
-- Push the closing operator into the mrow
373+
table.insert(children, child[1])
374+
-- Move the mrow into the msubsup, replacing the closing operator
375+
child[1] = children
376+
-- And insert the msubsup into the parent
377+
children = table.remove(stack)
378+
children[#children] = child
379+
else
380+
table.insert(children, child)
381+
end
382+
else
383+
table.insert(children, child)
384+
end
385+
end
386+
tree = #stack > 0 and stack[1] or children
329387
tree.command = "mrow"
330388
end
331-
tree.command = "mrow"
332389
elseif tree.id == "atom" then
333390
local codepoints = {}
334391
for _, cp in luautf8.codes(tree[1]) do

0 commit comments

Comments
 (0)