Skip to content

Commit

Permalink
Merge pull request #2184 from Omikhleia/math-overset-underset
Browse files Browse the repository at this point in the history
Math overset/underset and munder/mover spacing
  • Loading branch information
alerque authored Dec 2, 2024
2 parents 3263be3 + 41c3ad8 commit 5bfd6fc
Show file tree
Hide file tree
Showing 4 changed files with 177 additions and 1 deletion.
17 changes: 17 additions & 0 deletions packages/math/base-elements.lua
Original file line number Diff line number Diff line change
Expand Up @@ -732,8 +732,25 @@ local function isNotEmpty (element)
return element and (element:is_a(elements.terminal) or #element.children > 0)
end

local function unwrapSingleElementMrow (elt)
-- CODE SMELL.
-- For \overset or \underset in LaTeX, MathML would use <mover> or <munder>.
-- It would need to inherit the base's atom type, especially if the later is an operator
-- (binary, relational etc.), which is a fairly common case, e.g.
-- \overset{R}{=} (equality with a R above the equal in some Ramanujan summations),
-- but we can't remove 1-element mrow's in the math typesetter, or have them inherit
-- their base's atom type here above, because it breaks tables for some reasons
-- that I couldn't figure out.
if elt:is_a(elements.stackbox) and elt.direction == "H" and #elt.children == 1 then
return unwrapSingleElementMrow(elt.children[1])
else
return elt
end
end

function elements.underOver:_init (base, sub, sup)
elements.mbox._init(self)
base = unwrapSingleElementMrow(base)
self.atom = base.atom
self.base = base
self.sub = isNotEmpty(sub) and sub or nil
Expand Down
25 changes: 24 additions & 1 deletion packages/math/texlike.lua
Original file line number Diff line number Diff line change
Expand Up @@ -258,13 +258,22 @@ local commands = {}
local objType = {
tree = 1,
str = 2,
unknown = 3,
}

local function inferArgTypes_aux (accumulator, typeRequired, body)
if type(body) == "table" then
if body.id == "argument" then
local ret = accumulator
table.insert(ret, body.index, typeRequired)
while #ret < body.index do
-- Don't leave holes in the argument list.
-- This may happen if the argument are not used orderly, and the
-- entry might later be filled with the appropriate type... unless
-- the argument is not used at all.
-- CODE SMELL, but this recursive inference is hard to assess.
table.insert(ret, objType.unknown)
end
ret[body.index] = typeRequired
return ret
elseif body.id == "command" then
if commands[body.command] then
Expand Down Expand Up @@ -831,6 +840,20 @@ compileToMathML(
\def{phantom}{\mphantom{#1}}
\def{hphantom}{\mpadded[height=0, depth=0]{\mphantom{#1}}}
\def{vphantom}{\mpadded[width=0]{\mphantom{#1}}}
% Stacking commands
% Plain LaTeX \stackrel is only supposed to be used on binary relations.
% It's a poor naming choice, and a poor design choice as well.
% Package "stackrel" on CTAN redefine its for relational operators, and
% provides a \stackbin for binary operators.
% Users would, without respect for semantics, use them interchangeably.
% We use the same definition for both, and expect the MathML layer to handle
% the content as appropriate based on the actual operators...
\def{stackrel}{\mover{#2}{#1}}
\def{stackbin}{\mover{#2}{#1}}
% Package "amsmath" went with its own generic \overset and \underset.
\def{overset}{\mover{#2}{#1}}
\def{underset}{\munder{#2}{#1}}
]==],
})
)
Expand Down
111 changes: 111 additions & 0 deletions tests/math-underset-overset.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
Set paper size 297.6377985 419.5275636
Begin page
Mx 135.0361
My 27.5564
Set font Libertinus Math;10;400;Regular;normal;;;LTR
T 2720 w=7.0300 (nil)
Mx 144.8439
T 1960 w=9.1200 (nil)
Mx 156.7417
T 2721 w=5.8600 (nil)
Mx 135.0361
My 57.7204
T 2720 w=7.0300 (nil)
Mx 144.8439
T 1960 w=9.1200 (nil)
Mx 147.1823
My 64.0844
Set font Libertinus Math;8;400;Regular;normal;+ssty=1;;LTR
T 2751 w=4.4432 (nil)
Mx 156.7417
My 57.7204
Set font Libertinus Math;10;400;Regular;normal;;;LTR
T 2721 w=5.8600 (nil)
Mx 135.0361
My 98.6205
T 2720 w=7.0300 (nil)
Mx 147.1823
My 90.7365
Set font Libertinus Math;8;400;Regular;normal;+ssty=1;;LTR
T 2751 w=4.4432 (nil)
Mx 144.8439
My 98.6205
Set font Libertinus Math;10;400;Regular;normal;;;LTR
T 1960 w=9.1200 (nil)
Mx 156.7417
T 2721 w=5.8600 (nil)
Mx 132.4961
My 128.7846
T 2720 w=7.0300 (nil)
Mx 142.3039
T 2577 w=14.2000 (nil)
Mx 159.2817
T 2721 w=5.8600 (nil)
Mx 132.4961
My 160.5326
T 2720 w=7.0300 (nil)
Mx 144.1455
My 153.5526
Set font Libertinus Math;8;400;Regular;normal;+ssty=1;;LTR
T 69 70 71 w=10.5168 (nil)
Mx 142.3039
My 160.5326
Set font Libertinus Math;10;400;Regular;normal;;;LTR
T 2577 w=14.2000 (nil)
Mx 159.2817
T 2721 w=5.8600 (nil)
Mx 128.7121
My 190.6967
T 2720 w=7.0300 (nil)
Mx 142.3039
T 2577 w=14.2000 (nil)
Mx 138.5199
My 197.0607
Set font Libertinus Math;8;400;Regular;normal;+ssty=1;;LTR
T 66 77 78 80 84 85 w=21.7680 (nil)
Mx 163.0657
My 190.6967
Set font Libertinus Math;10;400;Regular;normal;;;LTR
T 2721 w=5.8600 (nil)
Mx 136.3561
My 222.8848
T 2720 w=7.0300 (nil)
Mx 146.1639
T 30 w=6.4800 (nil)
Mx 155.4217
T 2721 w=5.8600 (nil)
Mx 136.3561
My 253.6348
T 2720 w=7.0300 (nil)
Mx 147.0559
My 247.2848
Set font Libertinus Math;8;400;Regular;normal;+ssty=1;;LTR
T 51 w=4.6960 (nil)
Mx 146.1639
My 253.6348
Set font Libertinus Math;10;400;Regular;normal;;;LTR
T 30 w=6.4800 (nil)
Mx 155.4217
T 2721 w=5.8600 (nil)
Mx 136.5017
My 283.7989
T 2720 w=7.0300 (nil)
Mx 145.7539
T 2219 w=7.3000 (nil)
Mx 155.2761
T 2721 w=5.8600 (nil)
Mx 136.5017
My 313.9629
T 2720 w=7.0300 (nil)
Mx 145.7539
T 2219 w=7.3000 (nil)
Mx 146.4839
My 321.1889
Set font Libertinus Math;8;400;Regular;normal;+ssty=1;;LTR
T 41 w=5.8400 (nil)
Mx 155.2761
My 313.9629
Set font Libertinus Math;10;400;Regular;normal;;;LTR
T 2721 w=5.8600 (nil)
End page
Finish
25 changes: 25 additions & 0 deletions tests/math-underset-overset.sil
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
\begin[papersize=a6]{document}
\neverindent
\nofolios
\use[module=packages.math]
% Test for TeX-like operator stacking (overset/underset)

% Arrows have a rel atom type.
\math[mode=display]{A \rightarrow B}% For comparison
\math[mode=display]{A \underset{f}{\rightarrow} B}
\math[mode=display]{A \overset{f}{\rightarrow} B}
% Longer overset text.
\math[mode=display]{A \implies B}% For comparison
\math[mode=display]{A \overset{\text{def}}{\implies} B}
% Even long underset text (bigger than the operator)
\math[mode=display]{A \underset{\text{almost}}{\implies} B}

% The = has a rel atom type too
\math[mode=display]{A = B}% For comparison
\math[mode=display]{A \overset{\mathrm{R}}{=} B}

% \otimes has a bin atom type
\math[mode=display]{A \otimes B}% For comparison
\math[mode=display]{A \underset{\mathrm{H}}{\otimes} B}

\end{document}

0 comments on commit 5bfd6fc

Please sign in to comment.