• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

sile-typesetter / sile / 6713098919

31 Oct 2023 10:21PM UTC coverage: 52.831% (-21.8%) from 74.636%
6713098919

push

github

web-flow
Merge d0a2a1ee9 into b185d4972

45 of 45 new or added lines in 3 files covered. (100.0%)

8173 of 15470 relevant lines covered (52.83%)

6562.28 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

77.5
/packages/math/typesetter.lua
1
-- Interpret a MathML or TeX-like AST, typeset it and add it to the output.
2
local b = require("packages.math.base-elements")
3✔
3
local syms = require("packages.math.unicode-symbols")
3✔
4

5
-- Shorthands for atom types, used in the `atom` command option
6
local atomTypeShort = {
3✔
7
  ord = b.atomType.ordinary,
3✔
8
  big = b.atomType.bigOperator,
3✔
9
  bin = b.atomType.binaryOperator,
3✔
10
  rel = b.atomType.relationalOperator,
3✔
11
  open = b.atomType.openingSymbol,
3✔
12
  close = b.atomType.closeSymbol,
3✔
13
  punct = b.atomType.punctuationSymbol,
3✔
14
  inner = b.atomType.inner,
3✔
15
  over = b.atomType.overSymbol,
3✔
16
  under = b.atomType.underSymbol,
3✔
17
  accent = b.atomType.accentSymbol,
3✔
18
  radical = b.atomType.radicalSymbol,
3✔
19
  vcenter = b.atomType.vcenter
3✔
20
}
21

22
local ConvertMathML
23

24
local function convertChildren (tree)
25
  local mboxes = {}
132✔
26
  for _, n in ipairs(tree) do
720✔
27
    local box = ConvertMathML(nil, n)
588✔
28
    if box then table.insert(mboxes, box) end
588✔
29
  end
30
  return mboxes
132✔
31
end
32

33
-- convert MathML into mbox
34
function ConvertMathML (_, content)
3✔
35
  if content == nil or content.command == nil then return nil end
602✔
36
  if content.command == 'math' or content.command == 'mathml' then -- toplevel
378✔
37
    return b.stackbox('V', convertChildren(content))
28✔
38
  elseif content.command == 'mrow' then
364✔
39
    return b.stackbox('H', convertChildren(content))
56✔
40
  elseif content.command == 'mi' then
336✔
41
    local script = content.options.mathvariant and
82✔
42
      b.mathVariantToScriptType(content.options.mathvariant)
26✔
43
    local text = content[1]
82✔
44
    if type(text) ~= "string" then
82✔
45
      SU.error("mi command contains "..text..", which is not text")
×
46
    end
47
    script = script or (luautf8.len(text) == 1
82✔
48
      and b.scriptType.italic or b.scriptType.upright)
56✔
49
    return b.text('identifier', {}, script, text)
82✔
50
  elseif content.command == 'mo' then
254✔
51
    local script = content.options.mathvariant and
108✔
52
      b.mathVariantToScriptType(content.options.mathvariant) or b.scriptType.upright
114✔
53
    local text = content[1]
108✔
54
    local attributes = {}
108✔
55
    if syms.symbolDefaults[text] then
108✔
56
      for attribute,value in pairs(syms.symbolDefaults[text]) do
240✔
57
        attributes[attribute] = value
138✔
58
      end
59
    end
60
    if content.options.atom then
108✔
61
      if not atomTypeShort[content.options.atom] then
×
62
        SU.error("Unknown atom type " .. content.options.atom)
×
63
      else
64
        attributes.atom = atomTypeShort[content.options.atom]
×
65
      end
66
    end
67
    if type(text) ~= "string" then
108✔
68
      SU.error("mo command contains "..text..", which is not text")
×
69
    end
70
    return b.text('operator', attributes, script, text)
108✔
71
  elseif content.command == 'mn' then
146✔
72
    local script = content.options.mathvariant and
56✔
73
      b.mathVariantToScriptType(content.options.mathvariant) or b.scriptType.upright
56✔
74
    local text = content[1]
56✔
75
    if type(text) ~= "string" then
56✔
76
      SU.error("mn command contains "..text..", which is not text")
×
77
    end
78
    if string.sub(text, 1, 1) == "-" then
112✔
79
      text = "−"..string.sub(text, 2)
×
80
    end
81
    return b.text('number', {}, script, text)
56✔
82
  elseif content.command == "mspace" then
90✔
83
    return b.space(
×
84
      content.options.width,
×
85
      content.options.height,
×
86
      content.options.depth)
×
87
  elseif content.command == 'msub' then
90✔
88
    local children = convertChildren(content)
14✔
89
    if #children ~= 2 then SU.error('Wrong number of children in msub') end
14✔
90
    return b.newSubscript({ base=children[1], sub=children[2] })
14✔
91
  elseif content.command == 'msup' then
76✔
92
    local children = convertChildren(content)
16✔
93
    if #children ~= 2 then SU.error('Wrong number of children in msup') end
16✔
94
    return b.newSubscript({ base=children[1], sup=children[2] })
16✔
95
  elseif content.command == 'msubsup' then
60✔
96
    local children = convertChildren(content)
8✔
97
    if #children ~= 3 then SU.error('Wrong number of children in msubsup') end
8✔
98
    return b.newSubscript({ base=children[1], sub=children[2], sup=children[3] })
8✔
99
  elseif content.command == 'munder' then
52✔
100
    local children = convertChildren(content)
×
101
    if #children ~= 2 then SU.error('Wrong number of children in munder') end
×
102
    return b.newUnderOver({ base=children[1], sub=children[2] })
×
103
  elseif content.command == 'mover' then
52✔
104
    local children = convertChildren(content)
×
105
    if #children ~= 2 then SU.error('Wrong number of children in mover') end
×
106
    return b.newUnderOver({ base=children[1], sup=children[2] })
×
107
  elseif content.command == 'munderover' then
52✔
108
    local children = convertChildren(content)
×
109
    if #children ~= 3 then SU.error('Wrong number of children in munderover') end
×
110
    return b.newUnderOver({ base=children[1], sub=children[2], sup=children[3] })
×
111
  elseif content.command == 'mfrac' then
52✔
112
    local children = convertChildren(content)
×
113
    if #children ~= 2 then SU.error('Wrong number of children in mfrac: '
×
114
      ..#children)
×
115
    end
116
    return b.fraction(children[1], children[2])
×
117
  elseif content.command == "mtable" or content.command == "table" then
52✔
118
    local children = convertChildren(content)
4✔
119
    return b.table(children, content.options)
4✔
120
  elseif content.command == "mtr" then
48✔
121
    return b.mtr(convertChildren(content))
24✔
122
  elseif content.command == "mtd" then
36✔
123
    return b.stackbox("H", convertChildren(content))
72✔
124
  else
125
    SU.error("Unknown math command " .. content.command)
×
126
  end
127
end
128

129
local function handleMath (_, mbox, mode)
130
  if mode == 'display' then
14✔
131
    mbox.mode = b.mathMode.display
7✔
132
  elseif mode == 'text' then
7✔
133
    mbox.mode = b.mathMode.textCramped
7✔
134
  else
135
    SU.error('Unknown math mode '..mode)
×
136
  end
137

138
  SU.debug("math", function ()
28✔
139
    return "Resulting mbox: " .. tostring(mbox)
×
140
  end)
141
  mbox:styleDescendants()
14✔
142
  mbox:shapeTree()
14✔
143

144
  if mode == "display" then
14✔
145
    SILE.typesetter:endline()
7✔
146
    SILE.typesetter:pushExplicitVglue(SILE.settings:get("math.displayskip"))
14✔
147
    SILE.call("center", {}, function()
14✔
148
      SILE.typesetter:pushHorizontal(mbox)
7✔
149
    end)
150
    SILE.typesetter:endline()
7✔
151
    SILE.typesetter:pushExplicitVglue(SILE.settings:get("math.displayskip"))
21✔
152
  else
153
    SILE.typesetter:pushHorizontal(mbox)
7✔
154
  end
155
end
156

157
return { ConvertMathML, handleMath }
3✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc