temml 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +44 -0
- package/contrib/auto-render/README.md +89 -0
- package/contrib/auto-render/auto-render.js +128 -0
- package/contrib/auto-render/dist/auto-render.js +217 -0
- package/contrib/auto-render/dist/auto-render.min.js +1 -0
- package/contrib/auto-render/splitAtDelimiters.js +84 -0
- package/contrib/auto-render/test/auto-render-spec.js +234 -0
- package/contrib/auto-render/test/auto-render.js +217 -0
- package/contrib/auto-render/test/test_page.html +59 -0
- package/contrib/mhchem/README.md +26 -0
- package/contrib/mhchem/mhchem.js +1705 -0
- package/contrib/mhchem/mhchem.min.js +1 -0
- package/contrib/physics/README.md +20 -0
- package/contrib/physics/physics.js +131 -0
- package/contrib/texvc/README.md +23 -0
- package/contrib/texvc/texvc.js +61 -0
- package/dist/Temml-Asana.css +201 -0
- package/dist/Temml-Latin-Modern.css +216 -0
- package/dist/Temml-Libertinus.css +214 -0
- package/dist/Temml-Local.css +194 -0
- package/dist/Temml-STIX2.css +203 -0
- package/dist/Temml.woff2 +0 -0
- package/dist/temml.cjs +13122 -0
- package/dist/temml.js +11225 -0
- package/dist/temml.min.js +1 -0
- package/dist/temml.mjs +13120 -0
- package/dist/temmlPostProcess.js +70 -0
- package/package.json +34 -0
- package/src/Lexer.js +121 -0
- package/src/MacroExpander.js +437 -0
- package/src/Namespace.js +107 -0
- package/src/ParseError.js +64 -0
- package/src/Parser.js +977 -0
- package/src/Settings.js +49 -0
- package/src/SourceLocation.js +29 -0
- package/src/Style.js +144 -0
- package/src/Token.js +40 -0
- package/src/buildMathML.js +235 -0
- package/src/constants.js +25 -0
- package/src/defineEnvironment.js +25 -0
- package/src/defineFunction.js +69 -0
- package/src/defineMacro.js +11 -0
- package/src/domTree.js +185 -0
- package/src/environments/array.js +791 -0
- package/src/environments/cd.js +252 -0
- package/src/environments.js +8 -0
- package/src/functions/accent.js +127 -0
- package/src/functions/accentunder.js +38 -0
- package/src/functions/arrow.js +204 -0
- package/src/functions/cancelto.js +36 -0
- package/src/functions/char.js +33 -0
- package/src/functions/color.js +253 -0
- package/src/functions/cr.js +46 -0
- package/src/functions/def.js +259 -0
- package/src/functions/delimsizing.js +304 -0
- package/src/functions/enclose.js +193 -0
- package/src/functions/envTag.js +38 -0
- package/src/functions/environment.js +59 -0
- package/src/functions/font.js +123 -0
- package/src/functions/genfrac.js +333 -0
- package/src/functions/hbox.js +29 -0
- package/src/functions/horizBrace.js +32 -0
- package/src/functions/href.js +90 -0
- package/src/functions/html.js +95 -0
- package/src/functions/includegraphics.js +131 -0
- package/src/functions/kern.js +75 -0
- package/src/functions/label.js +29 -0
- package/src/functions/lap.js +75 -0
- package/src/functions/math.js +40 -0
- package/src/functions/mathchoice.js +41 -0
- package/src/functions/mclass.js +201 -0
- package/src/functions/multiscript.js +91 -0
- package/src/functions/not.js +46 -0
- package/src/functions/op.js +338 -0
- package/src/functions/operatorname.js +139 -0
- package/src/functions/ordgroup.js +9 -0
- package/src/functions/phantom.js +73 -0
- package/src/functions/pmb.js +31 -0
- package/src/functions/raise.js +68 -0
- package/src/functions/ref.js +28 -0
- package/src/functions/relax.js +16 -0
- package/src/functions/rule.js +52 -0
- package/src/functions/sizing.js +64 -0
- package/src/functions/smash.js +66 -0
- package/src/functions/sqrt.js +31 -0
- package/src/functions/styling.js +58 -0
- package/src/functions/supsub.js +135 -0
- package/src/functions/symbolsOp.js +53 -0
- package/src/functions/symbolsOrd.js +102 -0
- package/src/functions/symbolsSpacing.js +53 -0
- package/src/functions/tag.js +8 -0
- package/src/functions/text.js +75 -0
- package/src/functions/tip.js +63 -0
- package/src/functions/toggle.js +13 -0
- package/src/functions/verb.js +33 -0
- package/src/functions.js +57 -0
- package/src/linebreaking.js +159 -0
- package/src/macros.js +708 -0
- package/src/mathMLTree.js +175 -0
- package/src/parseNode.js +42 -0
- package/src/parseTree.js +40 -0
- package/src/postProcess.js +57 -0
- package/src/replace.js +225 -0
- package/src/stretchy.js +66 -0
- package/src/svg.js +110 -0
- package/src/symbols.js +972 -0
- package/src/tree.js +50 -0
- package/src/unicodeAccents.js +16 -0
- package/src/unicodeScripts.js +119 -0
- package/src/unicodeSupOrSub.js +108 -0
- package/src/unicodeSymbolBuilder.js +31 -0
- package/src/unicodeSymbols.js +320 -0
- package/src/units.js +109 -0
- package/src/utils.js +109 -0
- package/src/variant.js +103 -0
- package/temml.js +181 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import defineFunction, { ordargument } from "../defineFunction";
|
|
2
|
+
import symbols from "../symbols";
|
|
3
|
+
import * as mml from "../buildMathML";
|
|
4
|
+
import utils from "../utils"
|
|
5
|
+
|
|
6
|
+
defineFunction({
|
|
7
|
+
type: "not",
|
|
8
|
+
names: ["\\not"],
|
|
9
|
+
props: {
|
|
10
|
+
numArgs: 1,
|
|
11
|
+
primitive: true,
|
|
12
|
+
allowedInText: false
|
|
13
|
+
},
|
|
14
|
+
handler({ parser }, args) {
|
|
15
|
+
const isCharacterBox = utils.isCharacterBox(args[0])
|
|
16
|
+
let body
|
|
17
|
+
if (isCharacterBox) {
|
|
18
|
+
body = ordargument(args[0])
|
|
19
|
+
if (body[0].text.charAt(0) === "\\") {
|
|
20
|
+
body[0].text = symbols.math[body[0].text].replace
|
|
21
|
+
}
|
|
22
|
+
// \u0338 is the Unicode Combining Long Solidus Overlay
|
|
23
|
+
body[0].text = body[0].text.slice(0, 1) + "\u0338" + body[0].text.slice(1)
|
|
24
|
+
} else {
|
|
25
|
+
// When the argument is not a character box, TeX does an awkward, poorly placed overlay.
|
|
26
|
+
// We'll do the same.
|
|
27
|
+
const notNode = { type: "textord", mode: "math", text: "\u0338" }
|
|
28
|
+
const kernNode = { type: "kern", mode: "math", dimension: { number: -0.6, unit: "em" } }
|
|
29
|
+
body = [notNode, kernNode, args[0]]
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
type: "not",
|
|
33
|
+
mode: parser.mode,
|
|
34
|
+
body,
|
|
35
|
+
isCharacterBox
|
|
36
|
+
};
|
|
37
|
+
},
|
|
38
|
+
mathmlBuilder(group, style) {
|
|
39
|
+
if (group.isCharacterBox) {
|
|
40
|
+
const inner = mml.buildExpression(group.body, style);
|
|
41
|
+
return inner[0]
|
|
42
|
+
} else {
|
|
43
|
+
return mml.buildExpressionRow(group.body, style, true)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
});
|
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
// Limits, symbols
|
|
2
|
+
import defineFunction, { ordargument } from "../defineFunction";
|
|
3
|
+
import * as mathMLTree from "../mathMLTree";
|
|
4
|
+
import * as mml from "../buildMathML";
|
|
5
|
+
import { delimiters, delimiterSizes } from "./delimsizing"
|
|
6
|
+
|
|
7
|
+
// Some helpers
|
|
8
|
+
|
|
9
|
+
const ordAtomTypes = ["textord", "mathord", "atom"]
|
|
10
|
+
|
|
11
|
+
// Most operators have a large successor symbol, but these don't.
|
|
12
|
+
const noSuccessor = ["\\smallint"];
|
|
13
|
+
|
|
14
|
+
// Math operators (e.g. \sin) need a space between these types and themselves:
|
|
15
|
+
export const ordTypes = ["textord", "mathord", "ordgroup", "close", "leftright"];
|
|
16
|
+
|
|
17
|
+
const dels = ["}", "\\left", "\\middle", "\\right"]
|
|
18
|
+
const isDelimiter = str => str.length > 0 &&
|
|
19
|
+
(delimiters.includes(str) || delimiterSizes[str] || dels.includes(str))
|
|
20
|
+
|
|
21
|
+
// NOTE: Unlike most `builders`s, this one handles not only "op", but also
|
|
22
|
+
// "supsub" since some of them (like \int) can affect super/subscripting.
|
|
23
|
+
|
|
24
|
+
const mathmlBuilder = (group, style) => {
|
|
25
|
+
let node;
|
|
26
|
+
|
|
27
|
+
if (group.symbol) {
|
|
28
|
+
// This is a symbol. Just add the symbol.
|
|
29
|
+
node = new mathMLTree.MathNode("mo", [mml.makeText(group.name, group.mode)]);
|
|
30
|
+
if (noSuccessor.includes(group.name)) {
|
|
31
|
+
node.setAttribute("largeop", "false")
|
|
32
|
+
} else {
|
|
33
|
+
node.setAttribute("movablelimits", "false")
|
|
34
|
+
}
|
|
35
|
+
} else if (group.body) {
|
|
36
|
+
// This is an operator with children. Add them.
|
|
37
|
+
node = new mathMLTree.MathNode("mo", mml.buildExpression(group.body, style));
|
|
38
|
+
} else {
|
|
39
|
+
// This is a text operator. Add all of the characters from the operator's name.
|
|
40
|
+
node = new mathMLTree.MathNode("mi", [new mathMLTree.TextNode(group.name.slice(1))]);
|
|
41
|
+
|
|
42
|
+
if (!group.parentIsSupSub) {
|
|
43
|
+
// Append an invisible <mo>⁡</mo>.
|
|
44
|
+
// ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4
|
|
45
|
+
const operator = new mathMLTree.MathNode("mo", [mml.makeText("\u2061", "text")]);
|
|
46
|
+
const row = [node, operator]
|
|
47
|
+
// Set spacing
|
|
48
|
+
if (group.needsLeadingSpace) {
|
|
49
|
+
const lead = new mathMLTree.MathNode("mspace")
|
|
50
|
+
lead.setAttribute("width", "0.1667em") // thin space.
|
|
51
|
+
row.unshift(lead)
|
|
52
|
+
}
|
|
53
|
+
if (!group.isFollowedByDelimiter) {
|
|
54
|
+
const trail = new mathMLTree.MathNode("mspace")
|
|
55
|
+
trail.setAttribute("width", "0.1667em") // thin space.
|
|
56
|
+
row.push(trail)
|
|
57
|
+
}
|
|
58
|
+
node = new mathMLTree.MathNode("mrow", row)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return node;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const singleCharBigOps = {
|
|
66
|
+
"\u220F": "\\prod",
|
|
67
|
+
"\u2210": "\\coprod",
|
|
68
|
+
"\u2211": "\\sum",
|
|
69
|
+
"\u22c0": "\\bigwedge",
|
|
70
|
+
"\u22c1": "\\bigvee",
|
|
71
|
+
"\u22c2": "\\bigcap",
|
|
72
|
+
"\u22c3": "\\bigcup",
|
|
73
|
+
"\u2a00": "\\bigodot",
|
|
74
|
+
"\u2a01": "\\bigoplus",
|
|
75
|
+
"\u2a02": "\\bigotimes",
|
|
76
|
+
"\u2a04": "\\biguplus",
|
|
77
|
+
"\u2a05": "\\bigsqcap",
|
|
78
|
+
"\u2a06": "\\bigsqcup"
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
defineFunction({
|
|
82
|
+
type: "op",
|
|
83
|
+
names: [
|
|
84
|
+
"\\coprod",
|
|
85
|
+
"\\bigvee",
|
|
86
|
+
"\\bigwedge",
|
|
87
|
+
"\\biguplus",
|
|
88
|
+
"\\bigcap",
|
|
89
|
+
"\\bigcup",
|
|
90
|
+
"\\intop",
|
|
91
|
+
"\\prod",
|
|
92
|
+
"\\sum",
|
|
93
|
+
"\\bigotimes",
|
|
94
|
+
"\\bigoplus",
|
|
95
|
+
"\\bigodot",
|
|
96
|
+
"\\bigsqcap",
|
|
97
|
+
"\\bigsqcup",
|
|
98
|
+
"\\smallint",
|
|
99
|
+
"\u220F",
|
|
100
|
+
"\u2210",
|
|
101
|
+
"\u2211",
|
|
102
|
+
"\u22c0",
|
|
103
|
+
"\u22c1",
|
|
104
|
+
"\u22c2",
|
|
105
|
+
"\u22c3",
|
|
106
|
+
"\u2a00",
|
|
107
|
+
"\u2a01",
|
|
108
|
+
"\u2a02",
|
|
109
|
+
"\u2a04",
|
|
110
|
+
"\u2a06"
|
|
111
|
+
],
|
|
112
|
+
props: {
|
|
113
|
+
numArgs: 0
|
|
114
|
+
},
|
|
115
|
+
handler: ({ parser, funcName }, args) => {
|
|
116
|
+
let fName = funcName;
|
|
117
|
+
if (fName.length === 1) {
|
|
118
|
+
fName = singleCharBigOps[fName];
|
|
119
|
+
}
|
|
120
|
+
return {
|
|
121
|
+
type: "op",
|
|
122
|
+
mode: parser.mode,
|
|
123
|
+
limits: true,
|
|
124
|
+
parentIsSupSub: false,
|
|
125
|
+
symbol: true,
|
|
126
|
+
stack: false, // This is true for \stackrel{}, not here.
|
|
127
|
+
name: fName
|
|
128
|
+
};
|
|
129
|
+
},
|
|
130
|
+
mathmlBuilder
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// Note: calling defineFunction with a type that's already been defined only
|
|
134
|
+
// works because the same mathmlBuilder is being used.
|
|
135
|
+
defineFunction({
|
|
136
|
+
type: "op",
|
|
137
|
+
names: ["\\mathop"],
|
|
138
|
+
props: {
|
|
139
|
+
numArgs: 1,
|
|
140
|
+
primitive: true
|
|
141
|
+
},
|
|
142
|
+
handler: ({ parser }, args) => {
|
|
143
|
+
const body = args[0];
|
|
144
|
+
// It would be convienient to just wrap a <mo> around the argument.
|
|
145
|
+
// But if the argument is a <mi> or <mord>, that would be invalid MathML.
|
|
146
|
+
// In that case, we instead promote the text contents of the body to the parent.
|
|
147
|
+
const arr = (body.body) ? body.body : [body];
|
|
148
|
+
const isSymbol = arr.length === 1 && ordAtomTypes.includes(arr[0].type)
|
|
149
|
+
return {
|
|
150
|
+
type: "op",
|
|
151
|
+
mode: parser.mode,
|
|
152
|
+
limits: true,
|
|
153
|
+
parentIsSupSub: false,
|
|
154
|
+
symbol: isSymbol,
|
|
155
|
+
stack: false,
|
|
156
|
+
name: isSymbol ? arr[0].text : null,
|
|
157
|
+
body: isSymbol ? null : ordargument(body)
|
|
158
|
+
};
|
|
159
|
+
},
|
|
160
|
+
mathmlBuilder
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// There are 2 flags for operators; whether they produce limits in
|
|
164
|
+
// displaystyle, and whether they are symbols and should grow in
|
|
165
|
+
// displaystyle. These four groups cover the four possible choices.
|
|
166
|
+
|
|
167
|
+
const singleCharIntegrals = {
|
|
168
|
+
"\u222b": "\\int",
|
|
169
|
+
"\u222c": "\\iint",
|
|
170
|
+
"\u222d": "\\iiint",
|
|
171
|
+
"\u222e": "\\oint",
|
|
172
|
+
"\u222f": "\\oiint",
|
|
173
|
+
"\u2230": "\\oiiint",
|
|
174
|
+
"\u2231": "\\intclockwise",
|
|
175
|
+
"\u2232": "\\varointclockwise",
|
|
176
|
+
"\u2a0c": "\\iiiint",
|
|
177
|
+
"\u2a0d": "\\intbar",
|
|
178
|
+
"\u2a0e": "\\intBar",
|
|
179
|
+
"\u2a0f": "\\fint",
|
|
180
|
+
"\u2a12": "\\rppolint",
|
|
181
|
+
"\u2a13": "\\scpolint",
|
|
182
|
+
"\u2a15": "\\pointint",
|
|
183
|
+
"\u2a16": "\\sqint",
|
|
184
|
+
"\u2a17": "\\intlarhk",
|
|
185
|
+
"\u2a18": "\\intx",
|
|
186
|
+
"\u2a19": "\\intcap",
|
|
187
|
+
"\u2a1a": "\\intcup"
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
// No limits, not symbols
|
|
191
|
+
defineFunction({
|
|
192
|
+
type: "op",
|
|
193
|
+
names: [
|
|
194
|
+
"\\arcsin",
|
|
195
|
+
"\\arccos",
|
|
196
|
+
"\\arctan",
|
|
197
|
+
"\\arctg",
|
|
198
|
+
"\\arcctg",
|
|
199
|
+
"\\arg",
|
|
200
|
+
"\\ch",
|
|
201
|
+
"\\cos",
|
|
202
|
+
"\\cosec",
|
|
203
|
+
"\\cosh",
|
|
204
|
+
"\\cot",
|
|
205
|
+
"\\cotg",
|
|
206
|
+
"\\coth",
|
|
207
|
+
"\\csc",
|
|
208
|
+
"\\ctg",
|
|
209
|
+
"\\cth",
|
|
210
|
+
"\\deg",
|
|
211
|
+
"\\dim",
|
|
212
|
+
"\\exp",
|
|
213
|
+
"\\hom",
|
|
214
|
+
"\\ker",
|
|
215
|
+
"\\lg",
|
|
216
|
+
"\\ln",
|
|
217
|
+
"\\log",
|
|
218
|
+
"\\sec",
|
|
219
|
+
"\\sin",
|
|
220
|
+
"\\sinh",
|
|
221
|
+
"\\sh",
|
|
222
|
+
"\\sgn",
|
|
223
|
+
"\\tan",
|
|
224
|
+
"\\tanh",
|
|
225
|
+
"\\tg",
|
|
226
|
+
"\\th"
|
|
227
|
+
],
|
|
228
|
+
props: {
|
|
229
|
+
numArgs: 0
|
|
230
|
+
},
|
|
231
|
+
handler({ parser, funcName }) {
|
|
232
|
+
const prevAtomType = parser.prevAtomType
|
|
233
|
+
const next = parser.gullet.future().text
|
|
234
|
+
return {
|
|
235
|
+
type: "op",
|
|
236
|
+
mode: parser.mode,
|
|
237
|
+
limits: false,
|
|
238
|
+
parentIsSupSub: false,
|
|
239
|
+
symbol: false,
|
|
240
|
+
stack: false,
|
|
241
|
+
isFollowedByDelimiter: isDelimiter(next),
|
|
242
|
+
needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType),
|
|
243
|
+
name: funcName
|
|
244
|
+
};
|
|
245
|
+
},
|
|
246
|
+
mathmlBuilder
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
// Limits, not symbols
|
|
250
|
+
defineFunction({
|
|
251
|
+
type: "op",
|
|
252
|
+
names: ["\\det", "\\gcd", "\\inf", "\\lim", "\\max", "\\min", "\\Pr", "\\sup"],
|
|
253
|
+
props: {
|
|
254
|
+
numArgs: 0
|
|
255
|
+
},
|
|
256
|
+
handler({ parser, funcName }) {
|
|
257
|
+
const prevAtomType = parser.prevAtomType
|
|
258
|
+
const next = parser.gullet.future().text
|
|
259
|
+
return {
|
|
260
|
+
type: "op",
|
|
261
|
+
mode: parser.mode,
|
|
262
|
+
limits: true,
|
|
263
|
+
parentIsSupSub: false,
|
|
264
|
+
symbol: false,
|
|
265
|
+
stack: false,
|
|
266
|
+
isFollowedByDelimiter: isDelimiter(next),
|
|
267
|
+
needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType),
|
|
268
|
+
name: funcName
|
|
269
|
+
};
|
|
270
|
+
},
|
|
271
|
+
mathmlBuilder
|
|
272
|
+
});
|
|
273
|
+
|
|
274
|
+
// No limits, symbols
|
|
275
|
+
defineFunction({
|
|
276
|
+
type: "op",
|
|
277
|
+
names: [
|
|
278
|
+
"\\int",
|
|
279
|
+
"\\iint",
|
|
280
|
+
"\\iiint",
|
|
281
|
+
"\\iiiint",
|
|
282
|
+
"\\oint",
|
|
283
|
+
"\\oiint",
|
|
284
|
+
"\\oiiint",
|
|
285
|
+
"\\intclockwise",
|
|
286
|
+
"\\varointclockwise",
|
|
287
|
+
"\\intbar",
|
|
288
|
+
"\\intBar",
|
|
289
|
+
"\\fint",
|
|
290
|
+
"\\rppolint",
|
|
291
|
+
"\\scpolint",
|
|
292
|
+
"\\pointint",
|
|
293
|
+
"\\sqint",
|
|
294
|
+
"\\intlarhk",
|
|
295
|
+
"\\intx",
|
|
296
|
+
"\\intcap",
|
|
297
|
+
"\\intcup",
|
|
298
|
+
"\u222b",
|
|
299
|
+
"\u222c",
|
|
300
|
+
"\u222d",
|
|
301
|
+
"\u222e",
|
|
302
|
+
"\u222f",
|
|
303
|
+
"\u2230",
|
|
304
|
+
"\u2231",
|
|
305
|
+
"\u2232",
|
|
306
|
+
"\u2a0c",
|
|
307
|
+
"\u2a0d",
|
|
308
|
+
"\u2a0e",
|
|
309
|
+
"\u2a0f",
|
|
310
|
+
"\u2a12",
|
|
311
|
+
"\u2a13",
|
|
312
|
+
"\u2a15",
|
|
313
|
+
"\u2a16",
|
|
314
|
+
"\u2a17",
|
|
315
|
+
"\u2a18",
|
|
316
|
+
"\u2a19",
|
|
317
|
+
"\u2a1a"
|
|
318
|
+
],
|
|
319
|
+
props: {
|
|
320
|
+
numArgs: 0
|
|
321
|
+
},
|
|
322
|
+
handler({ parser, funcName }) {
|
|
323
|
+
let fName = funcName;
|
|
324
|
+
if (fName.length === 1) {
|
|
325
|
+
fName = singleCharIntegrals[fName];
|
|
326
|
+
}
|
|
327
|
+
return {
|
|
328
|
+
type: "op",
|
|
329
|
+
mode: parser.mode,
|
|
330
|
+
limits: false,
|
|
331
|
+
parentIsSupSub: false,
|
|
332
|
+
symbol: true,
|
|
333
|
+
stack: false,
|
|
334
|
+
name: fName
|
|
335
|
+
};
|
|
336
|
+
},
|
|
337
|
+
mathmlBuilder
|
|
338
|
+
});
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import defineFunction, { ordargument } from "../defineFunction"
|
|
2
|
+
import defineMacro from "../defineMacro";
|
|
3
|
+
import mathMLTree from "../mathMLTree"
|
|
4
|
+
import { spaceCharacter } from "./kern"
|
|
5
|
+
import { ordTypes } from "./op"
|
|
6
|
+
import { delimiters, delimiterSizes } from "./delimsizing"
|
|
7
|
+
|
|
8
|
+
import * as mml from "../buildMathML"
|
|
9
|
+
|
|
10
|
+
const dels = ["}", "\\left", "\\middle", "\\right"]
|
|
11
|
+
const isDelimiter = str => str.length > 0 &&
|
|
12
|
+
(delimiters.includes(str) || delimiterSizes[str] || dels.includes(str))
|
|
13
|
+
|
|
14
|
+
// NOTE: Unlike most builders, this one handles not only
|
|
15
|
+
// "operatorname", but also "supsub" since \operatorname* can
|
|
16
|
+
// affect super/subscripting.
|
|
17
|
+
|
|
18
|
+
const mathmlBuilder = (group, style) => {
|
|
19
|
+
let expression = mml.buildExpression(group.body, style.withFont("mathrm"))
|
|
20
|
+
|
|
21
|
+
// Is expression a string or has it something like a fraction?
|
|
22
|
+
let isAllString = true; // default
|
|
23
|
+
for (let i = 0; i < expression.length; i++) {
|
|
24
|
+
const node = expression[i]
|
|
25
|
+
if (node instanceof mathMLTree.MathNode) {
|
|
26
|
+
switch (node.type) {
|
|
27
|
+
case "mi":
|
|
28
|
+
case "mn":
|
|
29
|
+
case "ms":
|
|
30
|
+
case "mtext":
|
|
31
|
+
break; // Do nothing yet.
|
|
32
|
+
case "mspace":
|
|
33
|
+
{
|
|
34
|
+
if (node.attributes.width) {
|
|
35
|
+
const width = node.attributes.width.replace("em", "")
|
|
36
|
+
const ch = spaceCharacter(Number(width))
|
|
37
|
+
if (ch === "") {
|
|
38
|
+
isAllString = false
|
|
39
|
+
} else {
|
|
40
|
+
expression[i] = new mathMLTree.MathNode("mtext", [new mathMLTree.TextNode(ch)])
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
break
|
|
45
|
+
case "mo": {
|
|
46
|
+
const child = node.children[0]
|
|
47
|
+
if (node.children.length === 1 && child instanceof mathMLTree.TextNode) {
|
|
48
|
+
child.text = child.text.replace(/\u2212/, "-").replace(/\u2217/, "*")
|
|
49
|
+
} else {
|
|
50
|
+
isAllString = false
|
|
51
|
+
}
|
|
52
|
+
break
|
|
53
|
+
}
|
|
54
|
+
default:
|
|
55
|
+
isAllString = false
|
|
56
|
+
}
|
|
57
|
+
} else {
|
|
58
|
+
isAllString = false
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (isAllString) {
|
|
63
|
+
// Write a single TextNode instead of multiple nested tags.
|
|
64
|
+
const word = expression.map((node) => node.toText()).join("")
|
|
65
|
+
expression = [new mathMLTree.TextNode(word)]
|
|
66
|
+
} else if (
|
|
67
|
+
expression.length === 1
|
|
68
|
+
&& ["mover", "munder"].includes(expression[0].type) &&
|
|
69
|
+
(expression[0].children[0].type === "mi" || expression[0].children[0].type === "mtext")
|
|
70
|
+
) {
|
|
71
|
+
expression[0].children[0].type = "mi"
|
|
72
|
+
if (group.parentIsSupSub) {
|
|
73
|
+
return new mathMLTree.MathNode("mrow", expression)
|
|
74
|
+
} else {
|
|
75
|
+
const operator = new mathMLTree.MathNode("mo", [mml.makeText("\u2061", "text")])
|
|
76
|
+
return mathMLTree.newDocumentFragment([expression[0], operator])
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
let wrapper;
|
|
81
|
+
if (isAllString) {
|
|
82
|
+
wrapper = new mathMLTree.MathNode("mi", expression)
|
|
83
|
+
wrapper.setAttribute("mathvariant", "normal")
|
|
84
|
+
} else {
|
|
85
|
+
wrapper = new mathMLTree.MathNode("mrow", expression)
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (!group.parentIsSupSub) {
|
|
89
|
+
// Append an <mo>⁡</mo>.
|
|
90
|
+
// ref: https://www.w3.org/TR/REC-MathML/chap3_2.html#sec3.2.4
|
|
91
|
+
const operator = new mathMLTree.MathNode("mo", [mml.makeText("\u2061", "text")])
|
|
92
|
+
const fragment = [wrapper, operator]
|
|
93
|
+
if (group.needsLeadingSpace) {
|
|
94
|
+
// LaTeX gives operator spacing, but a <mi> gets ord spacing.
|
|
95
|
+
// So add a leading space.
|
|
96
|
+
const space = new mathMLTree.MathNode("mspace")
|
|
97
|
+
space.setAttribute("width", "0.1667em") // thin space.
|
|
98
|
+
fragment.unshift(space)
|
|
99
|
+
}
|
|
100
|
+
if (!group.isFollowedByDelimiter) {
|
|
101
|
+
const trail = new mathMLTree.MathNode("mspace")
|
|
102
|
+
trail.setAttribute("width", "0.1667em") // thin space.
|
|
103
|
+
fragment.push(trail)
|
|
104
|
+
}
|
|
105
|
+
return mathMLTree.newDocumentFragment(fragment)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return wrapper
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
// \operatorname
|
|
112
|
+
// amsopn.dtx: \mathop{#1\kern\z@\operator@font#3}\newmcodes@
|
|
113
|
+
defineFunction({
|
|
114
|
+
type: "operatorname",
|
|
115
|
+
names: ["\\operatorname@", "\\operatornamewithlimits"],
|
|
116
|
+
props: {
|
|
117
|
+
numArgs: 1,
|
|
118
|
+
allowedInArgument: true
|
|
119
|
+
},
|
|
120
|
+
handler: ({ parser, funcName }, args) => {
|
|
121
|
+
const body = args[0]
|
|
122
|
+
const prevAtomType = parser.prevAtomType
|
|
123
|
+
const next = parser.gullet.future().text
|
|
124
|
+
return {
|
|
125
|
+
type: "operatorname",
|
|
126
|
+
mode: parser.mode,
|
|
127
|
+
body: ordargument(body),
|
|
128
|
+
alwaysHandleSupSub: (funcName === "\\operatornamewithlimits"),
|
|
129
|
+
limits: false,
|
|
130
|
+
parentIsSupSub: false,
|
|
131
|
+
isFollowedByDelimiter: isDelimiter(next),
|
|
132
|
+
needsLeadingSpace: prevAtomType.length > 0 && ordTypes.includes(prevAtomType)
|
|
133
|
+
};
|
|
134
|
+
},
|
|
135
|
+
mathmlBuilder
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
defineMacro("\\operatorname",
|
|
139
|
+
"\\@ifstar\\operatornamewithlimits\\operatorname@");
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import defineFunction, { ordargument } from "../defineFunction";
|
|
2
|
+
import mathMLTree from "../mathMLTree";
|
|
3
|
+
import * as mml from "../buildMathML";
|
|
4
|
+
|
|
5
|
+
defineFunction({
|
|
6
|
+
type: "phantom",
|
|
7
|
+
names: ["\\phantom"],
|
|
8
|
+
props: {
|
|
9
|
+
numArgs: 1,
|
|
10
|
+
allowedInText: true
|
|
11
|
+
},
|
|
12
|
+
handler: ({ parser }, args) => {
|
|
13
|
+
const body = args[0];
|
|
14
|
+
return {
|
|
15
|
+
type: "phantom",
|
|
16
|
+
mode: parser.mode,
|
|
17
|
+
body: ordargument(body)
|
|
18
|
+
};
|
|
19
|
+
},
|
|
20
|
+
mathmlBuilder: (group, style) => {
|
|
21
|
+
const inner = mml.buildExpression(group.body, style);
|
|
22
|
+
return new mathMLTree.MathNode("mphantom", inner);
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
defineFunction({
|
|
27
|
+
type: "hphantom",
|
|
28
|
+
names: ["\\hphantom"],
|
|
29
|
+
props: {
|
|
30
|
+
numArgs: 1,
|
|
31
|
+
allowedInText: true
|
|
32
|
+
},
|
|
33
|
+
handler: ({ parser }, args) => {
|
|
34
|
+
const body = args[0];
|
|
35
|
+
return {
|
|
36
|
+
type: "hphantom",
|
|
37
|
+
mode: parser.mode,
|
|
38
|
+
body
|
|
39
|
+
};
|
|
40
|
+
},
|
|
41
|
+
mathmlBuilder: (group, style) => {
|
|
42
|
+
const inner = mml.buildExpression(ordargument(group.body), style);
|
|
43
|
+
const phantom = new mathMLTree.MathNode("mphantom", inner);
|
|
44
|
+
const node = new mathMLTree.MathNode("mpadded", [phantom]);
|
|
45
|
+
node.setAttribute("height", "0px");
|
|
46
|
+
node.setAttribute("depth", "0px");
|
|
47
|
+
return node;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
defineFunction({
|
|
52
|
+
type: "vphantom",
|
|
53
|
+
names: ["\\vphantom"],
|
|
54
|
+
props: {
|
|
55
|
+
numArgs: 1,
|
|
56
|
+
allowedInText: true
|
|
57
|
+
},
|
|
58
|
+
handler: ({ parser }, args) => {
|
|
59
|
+
const body = args[0];
|
|
60
|
+
return {
|
|
61
|
+
type: "vphantom",
|
|
62
|
+
mode: parser.mode,
|
|
63
|
+
body
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
mathmlBuilder: (group, style) => {
|
|
67
|
+
const inner = mml.buildExpression(ordargument(group.body), style);
|
|
68
|
+
const phantom = new mathMLTree.MathNode("mphantom", inner);
|
|
69
|
+
const node = new mathMLTree.MathNode("mpadded", [phantom]);
|
|
70
|
+
node.setAttribute("width", "0px");
|
|
71
|
+
return node;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import defineFunction, { ordargument } from "../defineFunction"
|
|
2
|
+
import { wrapWithMstyle } from "../mathMLTree"
|
|
3
|
+
import * as mml from "../buildMathML"
|
|
4
|
+
|
|
5
|
+
// \pmb is a simulation of bold font.
|
|
6
|
+
// The version of \pmb in ambsy.sty works by typesetting three copies of the argument
|
|
7
|
+
// with small offsets. We use CSS text-shadow.
|
|
8
|
+
// It's a hack. Not as good as a real bold font. Better than nothing.
|
|
9
|
+
|
|
10
|
+
defineFunction({
|
|
11
|
+
type: "pmb",
|
|
12
|
+
names: ["\\pmb"],
|
|
13
|
+
props: {
|
|
14
|
+
numArgs: 1,
|
|
15
|
+
allowedInText: true
|
|
16
|
+
},
|
|
17
|
+
handler({ parser }, args) {
|
|
18
|
+
return {
|
|
19
|
+
type: "pmb",
|
|
20
|
+
mode: parser.mode,
|
|
21
|
+
body: ordargument(args[0])
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
mathmlBuilder(group, style) {
|
|
25
|
+
const inner = mml.buildExpression(group.body, style)
|
|
26
|
+
// Wrap with an <mstyle> element.
|
|
27
|
+
const node = wrapWithMstyle(inner)
|
|
28
|
+
node.setAttribute("style", "text-shadow: 0.02em 0.01em 0.04px")
|
|
29
|
+
return node
|
|
30
|
+
}
|
|
31
|
+
})
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import defineFunction from "../defineFunction"
|
|
2
|
+
import { StyleLevel } from "../constants"
|
|
3
|
+
import mathMLTree from "../mathMLTree"
|
|
4
|
+
import { assertNodeType } from "../parseNode"
|
|
5
|
+
import { calculateSize } from "../units"
|
|
6
|
+
import * as mml from "../buildMathML"
|
|
7
|
+
|
|
8
|
+
const sign = num => num >= 0 ? "+" : "-"
|
|
9
|
+
|
|
10
|
+
// \raise, \lower, and \raisebox
|
|
11
|
+
|
|
12
|
+
const mathmlBuilder = (group, style) => {
|
|
13
|
+
const newStyle = style.withLevel(StyleLevel.TEXT)
|
|
14
|
+
const node = new mathMLTree.MathNode("mpadded", [mml.buildGroup(group.body, newStyle)])
|
|
15
|
+
const dy = calculateSize(group.dy, style)
|
|
16
|
+
node.setAttribute("voffset", dy.number + dy.unit)
|
|
17
|
+
const dyAbs = Math.abs(dy.number)
|
|
18
|
+
// The next two lines do not work in Chromium.
|
|
19
|
+
// TODO: Find some other way to adjust height and depth.
|
|
20
|
+
node.setAttribute("height", sign(dy.number) + dyAbs + dy.unit)
|
|
21
|
+
node.setAttribute("depth", sign(-dy.number) + dyAbs + dy.unit)
|
|
22
|
+
return node
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
defineFunction({
|
|
26
|
+
type: "raise",
|
|
27
|
+
names: ["\\raise", "\\lower"],
|
|
28
|
+
props: {
|
|
29
|
+
numArgs: 2,
|
|
30
|
+
argTypes: ["size", "primitive"],
|
|
31
|
+
primitive: true
|
|
32
|
+
},
|
|
33
|
+
handler({ parser, funcName }, args) {
|
|
34
|
+
const amount = assertNodeType(args[0], "size").value;
|
|
35
|
+
if (funcName === "\\lower") { amount.number *= -1 }
|
|
36
|
+
const body = args[1]
|
|
37
|
+
return {
|
|
38
|
+
type: "raise",
|
|
39
|
+
mode: parser.mode,
|
|
40
|
+
dy: amount,
|
|
41
|
+
body
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
mathmlBuilder
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
defineFunction({
|
|
49
|
+
type: "raise",
|
|
50
|
+
names: ["\\raisebox"],
|
|
51
|
+
props: {
|
|
52
|
+
numArgs: 2,
|
|
53
|
+
argTypes: ["size", "hbox"],
|
|
54
|
+
allowedInText: true
|
|
55
|
+
},
|
|
56
|
+
handler({ parser, funcName }, args) {
|
|
57
|
+
const amount = assertNodeType(args[0], "size").value
|
|
58
|
+
const body = args[1]
|
|
59
|
+
return {
|
|
60
|
+
type: "raise",
|
|
61
|
+
mode: parser.mode,
|
|
62
|
+
dy: amount,
|
|
63
|
+
body
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
mathmlBuilder
|
|
67
|
+
})
|
|
68
|
+
|