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

sile-typesetter / sile / 11989223534

23 Nov 2024 05:54PM UTC coverage: 64.386% (-4.2%) from 68.563%
11989223534

push

github

web-flow
Merge 144192218 into f0ddaed08

3 of 12 new or added lines in 1 file covered. (25.0%)

1080 existing lines in 35 files now uncovered.

12771 of 19835 relevant lines covered (64.39%)

4344.53 hits per line

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

79.17
/packages/math/init.lua
1
local base = require("packages.base")
13✔
2

3
local package = pl.class(base)
13✔
4
package._name = "math"
13✔
5

6
function package:_init ()
13✔
7
   base._init(self)
13✔
8
   local typesetter = require("packages.math.typesetter")
13✔
9
   self.ConvertMathML, self.handleMath = typesetter[1], typesetter[2]
13✔
10
   local texlike = require("packages.math.texlike")
13✔
11
   self.convertTexlike, self.compileToMathML = texlike[1], texlike[2]
13✔
12
   -- Register a new unit that is 1/18th of the current math font size
13
   SILE.registerUnit("mu", {
26✔
14
      relative = true,
15
      definition = function (value)
16
         return value * SILE.settings:get("math.font.size") / 18
1,532✔
17
      end,
18
   })
19
   self:loadPackage("counters")
13✔
20
end
21

22
function package.declareSettings (_)
13✔
23
   SILE.settings:declare({
13✔
24
      parameter = "math.font.family",
25
      type = "string",
26
      default = "Libertinus Math",
27
   })
28
   SILE.settings:declare({
13✔
29
      parameter = "math.font.style",
30
      type = "string",
31
      default = "Regular",
32
   })
33
   SILE.settings:declare({
13✔
34
      parameter = "math.font.weight",
35
      type = "integer",
36
      default = 400,
37
   })
38
   SILE.settings:declare({
13✔
39
      parameter = "math.font.script.feature",
40
      type = "string or nil",
41
      default = "ssty",
42
      help = "OpenType feature for the math script-style alternates (esp. primes), theoretically ssty",
43
   })
44
   SILE.settings:declare({
13✔
45
      parameter = "math.font.filename",
46
      type = "string",
47
      default = "",
48
   })
49
   SILE.settings:declare({
13✔
50
      parameter = "math.font.size",
51
      type = "integer",
52
      default = 10,
53
   })
54
   -- Whether to show debug boxes around mboxes
55
   SILE.settings:declare({
13✔
56
      parameter = "math.debug.boxes",
57
      type = "boolean",
58
      default = false,
59
   })
60
   SILE.settings:declare({
26✔
61
      parameter = "math.displayskip",
62
      type = "VGlue",
63
      default = SILE.types.node.vglue("2ex plus 1pt"),
26✔
64
   })
65

66
   -- Penalties for breaking before and after a display math formula
67
   -- See TeX's \predisplaypenalty and \postdisplaypenalty
68
   SILE.settings:declare({
13✔
69
      parameter = "math.predisplaypenalty",
70
      type = "integer",
71
      default = 10000, -- strict no break by default as in (La)TeX
72
      help = "Penalty for breaking before a display math formula",
73
   })
74
   SILE.settings:declare({
13✔
75
      parameter = "math.postdisplaypenalty",
76
      type = "integer",
77
      -- (La)TeX's default is 0 (a normal line break penalty allowing a break
78
      -- after a display math formula)
79
      -- See https://github.com/sile-typesetter/sile/issues/2160
80
      --    And see implementation in handleMath(): we are not yet doing the right
81
      --    things with respect to paragraphing, so setting a lower value for now
82
      --    to ease breaking after a display math formula rather than before
83
      --    when the formula is in the middle of a paragraph.
84
      --    (In TeX, these penalties would apply in horizontal mode, with a display
85
      --    math formula being a horizontal full-width box, our implementation
86
      --    currently use them as vertical penalties).
87
      default = -50,
88
      help = "Penalty for breaking after a display math formula",
89
   })
90
end
91

92
function package:registerCommands ()
13✔
93
   self:registerCommand("mathml", function (options, content)
26✔
94
      local mbox
95
      xpcall(function ()
44✔
96
         mbox = self:ConvertMathML(content)
44✔
97
      end, function (err)
44✔
98
         print(err)
×
99
         print(debug.traceback())
×
100
      end)
101
      self:handleMath(mbox, options)
22✔
102
   end)
103

104
   self:registerCommand("math", function (options, content)
26✔
105
      local mbox
106
      xpcall(function ()
114✔
107
         mbox = self:ConvertMathML(self:compileToMathML({}, self:convertTexlike(content)))
228✔
108
      end, function (err)
114✔
109
         print(err)
×
110
         print(debug.traceback())
×
111
      end)
112
      self:handleMath(mbox, options)
57✔
113
   end)
114

115
   self:registerCommand("math:numberingstyle", function (options, _)
26✔
UNCOV
116
      SILE.typesetter:typeset("(")
×
UNCOV
117
      if options.counter then
×
UNCOV
118
         SILE.call("show-counter", { id = options.counter })
×
UNCOV
119
      elseif options.number then
×
UNCOV
120
         SILE.typesetter:typeset(options.number)
×
121
      end
UNCOV
122
      SILE.typesetter:typeset(")")
×
123
   end)
124
end
125

126
package.documentation = [[
127
\begin{document}
128
\use[module=packages.math]
129
\set[parameter=math.font.family, value=Libertinus Math]
130
\set[parameter=math.font.size, value=11]
131
% Default verbatim font (Hack) is missing a few math symbols
132
\use[module=packages.font-fallback]
133
\font:add-fallback[family=Symbola]
134
\define[command=paragraph]{\smallskip\em{\process.}\novbreak\par}
135
The \autodoc:package{math} package provides typesetting of formulas directly in a SILE document.
136

137
\autodoc:note{Mathematical typesetting in SILE is still in its infancy.
138
As such, it lacks some features and may contain bugs.
139
Feedback and contributions are always welcome.}
140

141
\noindent To typeset mathematics, you will need an OpenType math font installed on your system.
142
By default, this package uses Libertinus Math, so it will fail if Libertinus Math can’t be found.
143
Another font may be specified via the setting \autodoc:setting{math.font.family}.
144
If required, you can set the font style and weight via \autodoc:setting{math.font.style} and \autodoc:setting{math.font.weight}.
145
The font size can be set via \autodoc:setting{math.font.size}.
146
The \autodoc:setting{math.font.script.feature} setting can be used to specify OpenType features for the math font, which are applied to the smaller script styles.
147
It defaults to \code{ssty} (script style alternates), notably to ensure that some symbols such as the prime, double prime, etc. are displayed correctly.
148
The default setting applies to Libertinus Math and well-designed math fonts, but some fonts may require different features.
149
(The STIX Two Math font has a stylitic set \code{ss04} from primes only, but also supports, according to its documentation, \code{ssty}, which provides other optical adjustments.)
150

151
\paragraph{MathML}
152
The first way to typeset math formulas is to enter them in the MathML format.
153
MathML is a standard for encoding mathematical notation for the Web and for other types of digital documents.
154
It is supported by a wide range of tools and represents the most promising format for unifying the encoding of mathematical notation, as well as improving its accessibility (e.g., to blind users).
155

156
To render an equation encoded in MathML, simply put it in a \code{mathml} command.
157
For example, the formula \mathml{\mrow{\msup{\mi{a}\mn{2}} \mo{+} \msup{\mi{b}\mn{2}} \mo{=} \msup{\mi{c}\mn{2}}}} was typeset by the following command:
158

159
\begin[type=autodoc:codeblock]{raw}
160
\mathml{
161
    \mrow{
162
        \msup{\mi{a}\mn{2}}
163
        \mo{+}
164
        \msup{\mi{b}\mn{2}}
165
        \mo{=}
166
        \msup{\mi{c}\mn{2}}
167
    }
168
}
169
\end{raw}
170

171
\noindent In an XML document, we could use the more classical XML syntax:
172

173
\begin[type=autodoc:codeblock]{raw}
174
<mathml>
175
    <mrow>
176
        <msup> <mi>a</mi> <mn>2</mn> </msup>
177
        <mo>+</mo>
178
        <msup> <mi>b</mi> <mn>2</mn> </msup>
179
        <mo>=</mo>
180
        <msup> <mi>c</mi> <mn>2</mn> </msup>
181
    </mrow>
182
</mathml>
183
\end{raw}
184

185
\noindent By default, formulas are integrated into the flow of text.
186
To typeset them on their own line, use the \autodoc:parameter{mode=display} option:
187

188
\mathml[mode=display]{
189
    \mrow{
190
        \msup{\mi{a}\mn{2}}
191
        \mo{+}
192
        \msup{\mi{b}\mn{2}}
193
        \mo{=}
194
        \msup{\mi{c}\mn{2}}
195
    }
196
}
197

198
\paragraph{TeX-like syntax}
199
As the previous examples illustrate, MathML is not really intended to be written by humans and quickly becomes very verbose.
200
That is why this package also provides a \code{math} command, which understands a syntax similar to the math syntax of TeX.
201
To typeset the above equation, one only has to type \code{\\math\{a^2 + b^2 = c^2\}}.
202

203
Here is a slightly more involved equation:
204

205
\begin[type=autodoc:codeblock]{raw}
206
\begin[mode=display]{math}
207
    \sum_{n=1}^\infty \frac{1}{n^2} = \frac{\pi^2}{6}
208
\end{math}
209
\end{raw}
210

211
\noindent This renders as:
212

213
\begin[mode=display]{math}
214
    \sum_{n=1}^\infty \frac{1}{n^2} = \frac{\pi^2}{6}
215
\end{math}
216

217
The general philosophy of the TeX-like syntax is to be a simple layer on top of MathML, and not to mimic perfectly the syntax of the LaTeX tool.
218
Its main difference from the SILE syntax is that \code{\\mycommand\{arg1\}\{arg2\}\{arg3\}} is translated into MathML as \code{<mycommand> arg1 arg2 arg3 </mycommand>} whereas in normal SILE syntax, the XML equivalent would be \code{<mycommand>arg1</mycommand> arg2 arg3}.
219

220
\code{\\sum}, \code{\\infty}, and \code{\\pi} are only shorthands for the Unicode characters \math{\sum}, \math{\infty} and \math{\pi}.
221
If it’s more convenient, you can use these Unicode characters directly.
222
The symbol shorthands are the same as in the TeX package \href[src=https://www.ctan.org/pkg/unicode-math]{\code{unicode-math}}.
223

224
The TeX-like syntax also supports several familiar constructs, pre-defined with appropriate spacing, movable limits and other properties, such as \code{\\sin}, \code{\\cos}, \code{\\lim}, etc.
225
These are just macro-definitions (see further below); for instance, \code{\\lim} is a shorthand for \code{\\mo[atom=op, movablelimits=true]\{lim\}}.
226
\begin[mode=display]{math}
227
    \sin 2\theta = 2\sin \theta \cos \theta
228
\end{math}
229
\begin[mode=display]{math}
230
    \math{\lim_{n\to\infty} F(n) = 0}
231
\end{math}
232

233
\code{\{formula\}} is a shorthand for \code{\\mrow\{formula\}}.
234
Delimiters—among other glyphs—stretch vertically to the size of their englobing \code{mrow}, which is useful for their size to adapt to the content.
235
SILE automatically wraps paired delimiters in such a construct, so these adapt to their inner content only.
236

237
\begin[type=autodoc:codeblock]{raw}
238
\Gamma (\frac{\zeta}{2}) + x^2(x+1)
239
\end{raw}
240

241
\noindent directly renders as
242

243
\begin[mode=display]{math}
244
    \Gamma (\frac{\zeta}{2}) + x^2(x+1)
245
\end{math}
246

247
\noindent which is neat.
248
But for cases when stretchy delimiters are not paired in an obvious way, these can end up too large.
249
To keep them small, you should put braces around the expression:
250

251
\begin[type=autodoc:codeblock]{raw}
252
\Vert v \Vert = \sqrt{x^2 + y^2} \text{ vs. } {\Vert v \Vert} = \sqrt{x^2 + y^2}
253
\end{raw}
254

255
\begin[mode=display]{math}
256
\Vert v \Vert = \sqrt{x^2 + y^2} \text{ vs. } {\Vert v \Vert} = \sqrt{x^2 + y^2}
257
\end{math}
258

259
\noindent To print a brace in a formula, you need to escape it with a backslash.
260

261
\paragraph{Token kinds}
262
In the \code{math} syntax, every individual letter is an identifier (MathML tag \code{mi}), every number is a… number (tag \code{mn}) and all other characters are operators (tag \code{mo}).
263
If this does not suit you, you can explicitly use the \code{\\mi}, \code{\\mn}, or \code{\\mo} tags.
264
For instance, \code{sin(x)} will be rendered as \math{sin(x)}, because SILE considers the letters s, i and n to be individual identifiers, and identifiers made of one character are italicized by default.
265
To avoid that, you can specify that \math{\mi{sin}} is an identifier by writing \code{\\mi\{sin\}(x)} and get: \math{\mi{sin}(x)}.
266
If you prefer it in “double struck” style, this is permitted by the \code{mathvariant} attribute: \code{\\mi[mathvariant=double-struck]\{sin\}(x)} renders as \math{\mi[mathvariant=double-struck]{sin}(x)}.
267

268
\paragraph{Atom types and spacing}
269
The current implementation does not follow the MathML rules for spacing, but rather the rules defined in the TeXbook, based on atom types.
270
Each token automatically gets assigned an atom type from the list below:
271
\begin{itemize}
272
  \item{\code{ord}: \code{mi} and \code{mn} tokens, as well as unclassified operators}
273
  \item{\code{op}: large operators like ‘\math{\sum}’ or ‘\math{\prod}’}
274
  \item{\code{bin}: binary operators like ‘\math{+}’ or ‘\math{\%}’}
275
  \item{\code{rel}: relation operators like ‘\math{=}’ or ‘\math{<}’}
276
  \item{\code{open}: opening operators like ‘\math{(}’ or ‘\math{[}’}
277
  \item{\code{close}: closing operators like ‘\math{)}’ or ‘\math{]}’}
278
  \item{\code{punct}: punctuation operators like ‘\math{,}’}
279
  % TODO: Those are defined in the 'math' package but appear to be unused
280
  %\item{\code{inner}}
281
  %\item{\code{over}}
282
  %\item{\code{under}}
283
  %\item{\code{accent}}
284
  %\item{\code{bothaccent}}
285
\end{itemize}
286
\noindent The spacing between any two successive tokens is set automatically based on their atom types, and hence may not reflect the actual spacing used in the input.
287
To make an operator behave like it has a certain atom type, you can use the \code{atom} attribute. For example, \code{a \\mo[atom=bin]\{div\} b} renders as \math[mode=display]{a \mo[atom=bin]{div} b.}
288

289
Spaces in math mode are defined in “math units” (mu), which are 1/18 of an em of the current \em{math} font (and are independent of the current text font size).
290
Standard spaces inserted automatically between tokens come in three varieties: thin (3 mu), medium (4 mu) and thick (5 mu).
291
If needed, you can insert them manually with the \code{\\thinspace} (or \code{\\,}), \code{\\medspace} (or \code{\\>}), and \code{\\thickspace} (or \code{\\;}) commands.
292
Negative space counterparts are available as \code{\\negthinspace} (or \code{\\!}), \code{\\negmedspace}, and \code{\\negthickspace}.
293
The \code{\\enspace}, \code{\\quad}, and \code{\\qquad} commands from normal text mode are also available, but the spaces they insert scale relative to the text font size.
294
Finally, you can add a space of any size using the \code{\\mspace[width=<dimension>]} command.
295

296
\paragraph{Macros}
297
To save you some typing, the math syntax lets you define macros with the following syntax:
298

299
\begin[type=autodoc:codeblock]{raw}
300
\def{macro-name}{macro-body}
301
\end{raw}
302

303
\noindent where in the macro’s body \code{#1}, \code{#2}, etc. will be replaced by the macro’s arguments.
304
For instance:
305

306
\begin[type=autodoc:codeblock]{raw}
307
\begin[mode=display]{math}
308
    \def{diff}{\mfrac{\mo{d}#1}{\mo{d}#2}}
309
    \def{bi}{\mi[mathvariant=bold-italic]{#1}}
310

311
    \diff{\bi{p}}{t} = ∑_i \bi{F}_i
312
\end{math}
313
\end{raw}
314

315
\noindent results in:
316

317
\begin[mode=display]{math}
318
  \def{diff}{\mfrac{\mo{d}#1}{\mo{d}#2}}
319
  \def{bi}{\mi[mathvariant=bold-italic]{#1}}
320
  \diff{\bi{p}}{t} = ∑_i \bi{F}_i
321
\end{math}
322

323
When macros are not enough, creating new mathematical elements is quite simple: one only needs to create a new class deriving from \code{mbox} (defined in \code{packages/math/base-elements.lua}) and define the \code{shape} and \code{output} methods.
324
\code{shape} must define the \code{width}, \code{height} and \code{depth} attributes of the element, while \code{output} must draw the actual output.
325
An \code{mbox} may have one or more children (for instance, a fraction has two children—its numerator and denominator).
326
The \code{shape} and \code{output} methods of the children are called automatically.
327

328
\paragraph{Matrices, aligned equations, and other tables}
329
Tabular math can be typeset using the \code{table} command (or equivalently the \code{mtable} MathML tag).
330
For instance, to typeset a matrix:
331

332
\begin[type=autodoc:codeblock]{raw}
333
\begin[mode=display]{math}
334
    (
335
    \table{
336
        1 & 2 & 7 \\
337
        0 & 5 & 3 \\
338
        8 & 2 & 1 \\
339
    }
340
    )
341
\end{math}
342
\end{raw}
343

344
\noindent will yield:
345

346
\begin[mode=display]{math}
347
  (\table{
348
       1 & 2 & 7 \\
349
       0 & 5 & 3 \\
350
       8 & 2 & 1 \\
351
  })
352
\end{math}
353

354
\noindent Tables may also be used to control the alignment of formulas:
355

356
\begin[type=autodoc:codeblock]{raw}
357
\begin[mode=display]{math}
358
    \{
359
    \table[columnalign=right center left]{
360
        u_0 &=& 1 \\
361
        u_1 &=& 1 \\
362
        u_n &=& u_{n−1} + u_{n−2}, \forall n ⩾ 2 \\
363
    }
364
\end{math}
365
\end{raw}
366

367
\begin[mode=display]{math}
368
    \{
369
    \table[columnalign=right center left]{
370
        u_0 &=& 1 \\
371
        u_1 &=& 1 \\
372
        u_n &=& u_{n−1} + u_{n−2}, \forall n ⩾ 2 \\
373
    }
374
\end{math}
375

376
\noindent Tables currently do not support all attributes required by the MathML standard, but they do allow to control spacing using the \code{rowspacing} and \code{columnspacing} options.
377

378
Finally, here is a little secret. This notation:
379

380
\begin[type=autodoc:codeblock]{raw}
381
\table{
382
    1 & 2 & 7 \\
383
    0 & 5 & 3 \\
384
    8 & 2 & 1 \\
385
}
386
\end{raw}
387

388
\noindent is strictly equivalent to this one:
389

390
\begin[type=autodoc:codeblock]{raw}
391
\table{
392
        {1} {2} {7}
393
    }{
394
        {0} {5} {3}
395
    }{
396
        {8} {2} {1}
397
    }
398
}
399
\end{raw}
400

401
\noindent In other words, the notation using \code{&} and \code{\\\\} is only a syntactic sugar for a two-dimensional array constructed with braces.
402

403
\paragraph{Numbered equations}
404
Equations can be numbered in display mode.
405

406
When \autodoc:parameter{numbered=true}, equations are numbered using a default “equation” counter:
407
\math[mode=display, numbered=true]{e^{i\pi} = -1}
408

409
A different counter can be set by using the option \autodoc:parameter{counter=<id>}, and this setting will also enable numbering.
410

411
It is also possible to impose direct numbering using the \autodoc:parameter{number=<value>} option.
412

413
The default numbering format is \autodoc:example{(n)}, but this style may be overridden by defining a custom \autodoc:command{\math:numberingstyle} command.
414
The \code{counter} or the direct value \code{number} is passed as a parameter to this hook, as well as any other options.
415

416
\paragraph{Missing features}
417
This package still lacks support for some mathematical constructs, but hopefully we’ll get there.
418
Among unsupported constructs are: decorating symbols with so-called accents, such as arrows or hats, “over” or “under” braces, and line breaking inside a formula.
419

420
\font:remove-fallback
421
\end{document}
422
]]
13✔
423

424
return package
13✔
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

© 2026 Coveralls, Inc