temml 0.9.1
Sign up to get free protection for your applications and to get access to all the features.
- 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,304 @@
|
|
1
|
+
import defineFunction from "../defineFunction";
|
2
|
+
import mathMLTree from "../mathMLTree";
|
3
|
+
import ParseError from "../ParseError";
|
4
|
+
import { assertNodeType, checkSymbolNodeType } from "../parseNode";
|
5
|
+
|
6
|
+
import * as mml from "../buildMathML";
|
7
|
+
|
8
|
+
// Extra data needed for the delimiter handler down below
|
9
|
+
export const delimiterSizes = {
|
10
|
+
"\\bigl": { mclass: "mopen", size: 1 },
|
11
|
+
"\\Bigl": { mclass: "mopen", size: 2 },
|
12
|
+
"\\biggl": { mclass: "mopen", size: 3 },
|
13
|
+
"\\Biggl": { mclass: "mopen", size: 4 },
|
14
|
+
"\\bigr": { mclass: "mclose", size: 1 },
|
15
|
+
"\\Bigr": { mclass: "mclose", size: 2 },
|
16
|
+
"\\biggr": { mclass: "mclose", size: 3 },
|
17
|
+
"\\Biggr": { mclass: "mclose", size: 4 },
|
18
|
+
"\\bigm": { mclass: "mrel", size: 1 },
|
19
|
+
"\\Bigm": { mclass: "mrel", size: 2 },
|
20
|
+
"\\biggm": { mclass: "mrel", size: 3 },
|
21
|
+
"\\Biggm": { mclass: "mrel", size: 4 },
|
22
|
+
"\\big": { mclass: "mord", size: 1 },
|
23
|
+
"\\Big": { mclass: "mord", size: 2 },
|
24
|
+
"\\bigg": { mclass: "mord", size: 3 },
|
25
|
+
"\\Bigg": { mclass: "mord", size: 4 }
|
26
|
+
};
|
27
|
+
|
28
|
+
export const delimiters = [
|
29
|
+
"(",
|
30
|
+
"\\lparen",
|
31
|
+
")",
|
32
|
+
"\\rparen",
|
33
|
+
"[",
|
34
|
+
"\\lbrack",
|
35
|
+
"]",
|
36
|
+
"\\rbrack",
|
37
|
+
"\\{",
|
38
|
+
"\\lbrace",
|
39
|
+
"\\}",
|
40
|
+
"\\rbrace",
|
41
|
+
"\\lfloor",
|
42
|
+
"\\rfloor",
|
43
|
+
"\u230a",
|
44
|
+
"\u230b",
|
45
|
+
"\\lceil",
|
46
|
+
"\\rceil",
|
47
|
+
"\u2308",
|
48
|
+
"\u2309",
|
49
|
+
"<",
|
50
|
+
">",
|
51
|
+
"\\langle",
|
52
|
+
"\u27e8",
|
53
|
+
"\\rangle",
|
54
|
+
"\u27e9",
|
55
|
+
"\\lt",
|
56
|
+
"\\gt",
|
57
|
+
"\\lvert",
|
58
|
+
"\\rvert",
|
59
|
+
"\\lVert",
|
60
|
+
"\\rVert",
|
61
|
+
"\\lgroup",
|
62
|
+
"\\rgroup",
|
63
|
+
"\u27ee",
|
64
|
+
"\u27ef",
|
65
|
+
"\\lmoustache",
|
66
|
+
"\\rmoustache",
|
67
|
+
"\u23b0",
|
68
|
+
"\u23b1",
|
69
|
+
"\\llbracket",
|
70
|
+
"\\rrbracket",
|
71
|
+
"\u27e6",
|
72
|
+
"\u27e6",
|
73
|
+
"\\lBrace",
|
74
|
+
"\\rBrace",
|
75
|
+
"\u2983",
|
76
|
+
"\u2984",
|
77
|
+
"/",
|
78
|
+
"\\backslash",
|
79
|
+
"|",
|
80
|
+
"\\vert",
|
81
|
+
"\\|",
|
82
|
+
"\\Vert",
|
83
|
+
"\\uparrow",
|
84
|
+
"\\Uparrow",
|
85
|
+
"\\downarrow",
|
86
|
+
"\\Downarrow",
|
87
|
+
"\\updownarrow",
|
88
|
+
"\\Updownarrow",
|
89
|
+
"."
|
90
|
+
];
|
91
|
+
|
92
|
+
// Metrics of the different sizes. Found by looking at TeX's output of
|
93
|
+
// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
|
94
|
+
// Used to create stacked delimiters of appropriate sizes in makeSizedDelim.
|
95
|
+
const sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0];
|
96
|
+
|
97
|
+
// Delimiter functions
|
98
|
+
function checkDelimiter(delim, context) {
|
99
|
+
if (delim.type === "ordgroup" && delim.body.length === 1 && delim.body[0].text === "\u2044") {
|
100
|
+
// Recover "/" from the zero spacing group. (See macros.js)
|
101
|
+
delim = { type: "textord", text: "/", mode: "math" }
|
102
|
+
}
|
103
|
+
const symDelim = checkSymbolNodeType(delim)
|
104
|
+
if (symDelim && delimiters.includes(symDelim.text)) {
|
105
|
+
// If a character is not in the MathML operator dictionary, it will not stretch.
|
106
|
+
// Replace such characters w/characters that will stretch.
|
107
|
+
if (["<", "\\lt"].includes(symDelim.text)) { symDelim.text = "⟨" }
|
108
|
+
if ([">", "\\gt"].includes(symDelim.text)) { symDelim.text = "⟩" }
|
109
|
+
if (symDelim.text === "/") { symDelim.text = "\u2215" }
|
110
|
+
if (symDelim.text === "\\backslash") { symDelim.text = "\u2216" }
|
111
|
+
return symDelim;
|
112
|
+
} else if (symDelim) {
|
113
|
+
throw new ParseError(`Invalid delimiter '${symDelim.text}' after '${context.funcName}'`, delim);
|
114
|
+
} else {
|
115
|
+
throw new ParseError(`Invalid delimiter type '${delim.type}'`, delim);
|
116
|
+
}
|
117
|
+
}
|
118
|
+
|
119
|
+
defineFunction({
|
120
|
+
type: "delimsizing",
|
121
|
+
names: [
|
122
|
+
"\\bigl",
|
123
|
+
"\\Bigl",
|
124
|
+
"\\biggl",
|
125
|
+
"\\Biggl",
|
126
|
+
"\\bigr",
|
127
|
+
"\\Bigr",
|
128
|
+
"\\biggr",
|
129
|
+
"\\Biggr",
|
130
|
+
"\\bigm",
|
131
|
+
"\\Bigm",
|
132
|
+
"\\biggm",
|
133
|
+
"\\Biggm",
|
134
|
+
"\\big",
|
135
|
+
"\\Big",
|
136
|
+
"\\bigg",
|
137
|
+
"\\Bigg"
|
138
|
+
],
|
139
|
+
props: {
|
140
|
+
numArgs: 1,
|
141
|
+
argTypes: ["primitive"]
|
142
|
+
},
|
143
|
+
handler: (context, args) => {
|
144
|
+
const delim = checkDelimiter(args[0], context);
|
145
|
+
|
146
|
+
return {
|
147
|
+
type: "delimsizing",
|
148
|
+
mode: context.parser.mode,
|
149
|
+
size: delimiterSizes[context.funcName].size,
|
150
|
+
mclass: delimiterSizes[context.funcName].mclass,
|
151
|
+
delim: delim.text
|
152
|
+
};
|
153
|
+
},
|
154
|
+
mathmlBuilder: (group) => {
|
155
|
+
const children = [];
|
156
|
+
|
157
|
+
if (group.delim === ".") { group.delim = "" }
|
158
|
+
children.push(mml.makeText(group.delim, group.mode));
|
159
|
+
|
160
|
+
const node = new mathMLTree.MathNode("mo", children);
|
161
|
+
|
162
|
+
if (group.mclass === "mopen" || group.mclass === "mclose") {
|
163
|
+
// Only some of the delimsizing functions act as fences, and they
|
164
|
+
// return "mopen" or "mclose" mclass.
|
165
|
+
node.setAttribute("fence", "true");
|
166
|
+
} else {
|
167
|
+
// Explicitly disable fencing if it's not a fence, to override the
|
168
|
+
// defaults.
|
169
|
+
node.setAttribute("fence", "false");
|
170
|
+
}
|
171
|
+
if (group.delim === "\u2216" || group.delim.indexOf("arrow") > -1) {
|
172
|
+
// \backslash is not in the operator dictionary,
|
173
|
+
// so we have to explicitly set stretchy to true.
|
174
|
+
node.setAttribute("stretchy", "true")
|
175
|
+
}
|
176
|
+
|
177
|
+
node.setAttribute("symmetric", "true"); // Needed for tall arrows in Firefox.
|
178
|
+
node.setAttribute("minsize", sizeToMaxHeight[group.size] + "em");
|
179
|
+
// Don't set the maxsize attribute. It's broken in Chromium.
|
180
|
+
return node;
|
181
|
+
}
|
182
|
+
});
|
183
|
+
|
184
|
+
function assertParsed(group) {
|
185
|
+
if (!group.body) {
|
186
|
+
throw new Error("Bug: The leftright ParseNode wasn't fully parsed.");
|
187
|
+
}
|
188
|
+
}
|
189
|
+
|
190
|
+
defineFunction({
|
191
|
+
type: "leftright-right",
|
192
|
+
names: ["\\right"],
|
193
|
+
props: {
|
194
|
+
numArgs: 1,
|
195
|
+
argTypes: ["primitive"]
|
196
|
+
},
|
197
|
+
handler: (context, args) => {
|
198
|
+
// \left case below triggers parsing of \right in
|
199
|
+
// `const right = parser.parseFunction();`
|
200
|
+
// uses this return value.
|
201
|
+
const color = context.parser.gullet.macros.get("\\current@color");
|
202
|
+
if (color && typeof color !== "string") {
|
203
|
+
throw new ParseError("\\current@color set to non-string in \\right");
|
204
|
+
}
|
205
|
+
return {
|
206
|
+
type: "leftright-right",
|
207
|
+
mode: context.parser.mode,
|
208
|
+
delim: checkDelimiter(args[0], context).text,
|
209
|
+
color // undefined if not set via \color
|
210
|
+
};
|
211
|
+
}
|
212
|
+
});
|
213
|
+
|
214
|
+
defineFunction({
|
215
|
+
type: "leftright",
|
216
|
+
names: ["\\left"],
|
217
|
+
props: {
|
218
|
+
numArgs: 1,
|
219
|
+
argTypes: ["primitive"]
|
220
|
+
},
|
221
|
+
handler: (context, args) => {
|
222
|
+
const delim = checkDelimiter(args[0], context);
|
223
|
+
|
224
|
+
const parser = context.parser;
|
225
|
+
// Parse out the implicit body
|
226
|
+
++parser.leftrightDepth;
|
227
|
+
// parseExpression stops before '\\right'
|
228
|
+
const body = parser.parseExpression(false);
|
229
|
+
--parser.leftrightDepth;
|
230
|
+
// Check the next token
|
231
|
+
parser.expect("\\right", false);
|
232
|
+
const right = assertNodeType(parser.parseFunction(), "leftright-right");
|
233
|
+
return {
|
234
|
+
type: "leftright",
|
235
|
+
mode: parser.mode,
|
236
|
+
body,
|
237
|
+
left: delim.text,
|
238
|
+
right: right.delim,
|
239
|
+
rightColor: right.color
|
240
|
+
};
|
241
|
+
},
|
242
|
+
mathmlBuilder: (group, style) => {
|
243
|
+
assertParsed(group);
|
244
|
+
const inner = mml.buildExpression(group.body, style);
|
245
|
+
|
246
|
+
if (group.left === ".") { group.left = "" }
|
247
|
+
const leftNode = new mathMLTree.MathNode("mo", [mml.makeText(group.left, group.mode)]);
|
248
|
+
leftNode.setAttribute("fence", "true")
|
249
|
+
leftNode.setAttribute("form", "prefix")
|
250
|
+
if (group.left === "\u2216" || group.left.indexOf("arrow") > -1) {
|
251
|
+
leftNode.setAttribute("stretchy", "true")
|
252
|
+
}
|
253
|
+
inner.unshift(leftNode)
|
254
|
+
|
255
|
+
if (group.right === ".") { group.right = "" }
|
256
|
+
const rightNode = new mathMLTree.MathNode("mo", [mml.makeText(group.right, group.mode)]);
|
257
|
+
rightNode.setAttribute("fence", "true")
|
258
|
+
rightNode.setAttribute("form", "postfix")
|
259
|
+
if (group.right === "\u2216" || group.right.indexOf("arrow") > -1) {
|
260
|
+
rightNode.setAttribute("stretchy", "true")
|
261
|
+
}
|
262
|
+
if (group.rightColor) { rightNode.setAttribute("mathcolor", group.rightColor) }
|
263
|
+
inner.push(rightNode)
|
264
|
+
|
265
|
+
return mml.makeRow(inner);
|
266
|
+
}
|
267
|
+
});
|
268
|
+
|
269
|
+
defineFunction({
|
270
|
+
type: "middle",
|
271
|
+
names: ["\\middle"],
|
272
|
+
props: {
|
273
|
+
numArgs: 1,
|
274
|
+
argTypes: ["primitive"]
|
275
|
+
},
|
276
|
+
handler: (context, args) => {
|
277
|
+
const delim = checkDelimiter(args[0], context);
|
278
|
+
if (!context.parser.leftrightDepth) {
|
279
|
+
throw new ParseError("\\middle without preceding \\left", delim);
|
280
|
+
}
|
281
|
+
|
282
|
+
return {
|
283
|
+
type: "middle",
|
284
|
+
mode: context.parser.mode,
|
285
|
+
delim: delim.text
|
286
|
+
};
|
287
|
+
},
|
288
|
+
mathmlBuilder: (group, style) => {
|
289
|
+
const textNode = mml.makeText(group.delim, group.mode);
|
290
|
+
const middleNode = new mathMLTree.MathNode("mo", [textNode]);
|
291
|
+
middleNode.setAttribute("fence", "true");
|
292
|
+
if (group.delim.indexOf("arrow") > -1) {
|
293
|
+
middleNode.setAttribute("stretchy", "true")
|
294
|
+
}
|
295
|
+
// The next line is not semantically correct, but
|
296
|
+
// Chromium fails to stretch if it is not there.
|
297
|
+
middleNode.setAttribute("form", "prefix")
|
298
|
+
// MathML gives 5/18em spacing to each <mo> element.
|
299
|
+
// \middle should get delimiter spacing instead.
|
300
|
+
middleNode.setAttribute("lspace", "0.05em");
|
301
|
+
middleNode.setAttribute("rspace", "0.05em");
|
302
|
+
return middleNode;
|
303
|
+
}
|
304
|
+
});
|
@@ -0,0 +1,193 @@
|
|
1
|
+
import defineFunction from "../defineFunction";
|
2
|
+
import mathMLTree from "../mathMLTree";
|
3
|
+
import { assertNodeType } from "../parseNode";
|
4
|
+
import { colorFromSpec, validateColor } from "./color"
|
5
|
+
import * as mml from "../buildMathML";
|
6
|
+
|
7
|
+
const padding = _ => {
|
8
|
+
const node = new mathMLTree.MathNode("mspace")
|
9
|
+
node.setAttribute("width", "3pt")
|
10
|
+
return node
|
11
|
+
}
|
12
|
+
|
13
|
+
const mathmlBuilder = (group, style) => {
|
14
|
+
let node
|
15
|
+
if (group.label.indexOf("colorbox") > -1) {
|
16
|
+
// Chrome mpadded +width attribute is broken. Insert <mspace>
|
17
|
+
node = new mathMLTree.MathNode("mpadded", [
|
18
|
+
padding(),
|
19
|
+
mml.buildGroup(group.body, style),
|
20
|
+
padding()
|
21
|
+
])
|
22
|
+
} else {
|
23
|
+
node = new mathMLTree.MathNode("menclose", [mml.buildGroup(group.body, style)])
|
24
|
+
}
|
25
|
+
switch (group.label) {
|
26
|
+
case "\\overline":
|
27
|
+
node.setAttribute("notation", "top")
|
28
|
+
node.style.padding = "0.1em 0 0 0"
|
29
|
+
node.style.borderTop = "0.065em solid"
|
30
|
+
break
|
31
|
+
case "\\underline":
|
32
|
+
node.setAttribute("notation", "bottom")
|
33
|
+
node.style.padding = "0 0 0.1em 0"
|
34
|
+
node.style.borderBottom = "0.065em solid"
|
35
|
+
break
|
36
|
+
case "\\cancel":
|
37
|
+
node.setAttribute("notation", "updiagonalstrike");
|
38
|
+
node.classes.push("cancel")
|
39
|
+
break
|
40
|
+
case "\\bcancel":
|
41
|
+
node.setAttribute("notation", "downdiagonalstrike");
|
42
|
+
node.classes.push("bcancel")
|
43
|
+
break
|
44
|
+
/*
|
45
|
+
case "\\longdiv":
|
46
|
+
node.setAttribute("notation", "longdiv");
|
47
|
+
break
|
48
|
+
case "\\phase":
|
49
|
+
node.setAttribute("notation", "phasorangle");
|
50
|
+
break */
|
51
|
+
case "\\angl":
|
52
|
+
node.setAttribute("notation", "actuarial")
|
53
|
+
node.style.padding = "0.03889em 0.03889em 0 0.03889em"
|
54
|
+
node.style.borderTop = "0.049em solid"
|
55
|
+
node.style.borderRight = "0.049em solid"
|
56
|
+
node.style.marginRight = "0.03889em"
|
57
|
+
break
|
58
|
+
case "\\sout":
|
59
|
+
node.setAttribute("notation", "horizontalstrike");
|
60
|
+
node.style["text-decoration"] = "line-through 0.08em solid"
|
61
|
+
break
|
62
|
+
case "\\fbox":
|
63
|
+
node.setAttribute("notation", "box");
|
64
|
+
node.style = { padding: "3pt", border: "1px solid" }
|
65
|
+
break
|
66
|
+
case "\\fcolorbox":
|
67
|
+
case "\\colorbox": {
|
68
|
+
// <menclose> doesn't have a good notation option for \colorbox.
|
69
|
+
// So use <mpadded> instead. Set some attributes that come
|
70
|
+
// included with <menclose>.
|
71
|
+
//const fboxsep = 3; // 3 pt from LaTeX source2e
|
72
|
+
//node.setAttribute("height", `+${2 * fboxsep}pt`)
|
73
|
+
//node.setAttribute("voffset", `${fboxsep}pt`)
|
74
|
+
const style = { padding: "3pt 0 3pt 0" }
|
75
|
+
|
76
|
+
if (group.label === "\\fcolorbox") {
|
77
|
+
style.border = "0.06em solid " + String(group.borderColor)
|
78
|
+
}
|
79
|
+
node.style = style
|
80
|
+
break
|
81
|
+
}
|
82
|
+
case "\\xcancel":
|
83
|
+
node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
|
84
|
+
node.classes.push("xcancel")
|
85
|
+
break
|
86
|
+
}
|
87
|
+
if (group.backgroundColor) {
|
88
|
+
node.setAttribute("mathbackground", group.backgroundColor);
|
89
|
+
}
|
90
|
+
return node;
|
91
|
+
};
|
92
|
+
|
93
|
+
defineFunction({
|
94
|
+
type: "enclose",
|
95
|
+
names: ["\\colorbox"],
|
96
|
+
props: {
|
97
|
+
numArgs: 2,
|
98
|
+
numOptionalArgs: 1,
|
99
|
+
allowedInText: true,
|
100
|
+
argTypes: ["raw", "raw", "text"]
|
101
|
+
},
|
102
|
+
handler({ parser, funcName }, args, optArgs) {
|
103
|
+
const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string
|
104
|
+
let color = ""
|
105
|
+
if (model) {
|
106
|
+
const spec = assertNodeType(args[0], "raw").string
|
107
|
+
color = colorFromSpec(model, spec)
|
108
|
+
} else {
|
109
|
+
color = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros)
|
110
|
+
}
|
111
|
+
const body = args[1];
|
112
|
+
return {
|
113
|
+
type: "enclose",
|
114
|
+
mode: parser.mode,
|
115
|
+
label: funcName,
|
116
|
+
backgroundColor: color,
|
117
|
+
body
|
118
|
+
};
|
119
|
+
},
|
120
|
+
mathmlBuilder
|
121
|
+
});
|
122
|
+
|
123
|
+
defineFunction({
|
124
|
+
type: "enclose",
|
125
|
+
names: ["\\fcolorbox"],
|
126
|
+
props: {
|
127
|
+
numArgs: 3,
|
128
|
+
numOptionalArgs: 1,
|
129
|
+
allowedInText: true,
|
130
|
+
argTypes: ["raw", "raw", "raw", "text"]
|
131
|
+
},
|
132
|
+
handler({ parser, funcName }, args, optArgs) {
|
133
|
+
const model = optArgs[0] && assertNodeType(optArgs[0], "raw").string
|
134
|
+
let borderColor = ""
|
135
|
+
let backgroundColor
|
136
|
+
if (model) {
|
137
|
+
const borderSpec = assertNodeType(args[0], "raw").string
|
138
|
+
const backgroundSpec = assertNodeType(args[0], "raw").string
|
139
|
+
borderColor = colorFromSpec(model, borderSpec)
|
140
|
+
backgroundColor = colorFromSpec(model, backgroundSpec)
|
141
|
+
} else {
|
142
|
+
borderColor = validateColor(assertNodeType(args[0], "raw").string, parser.gullet.macros)
|
143
|
+
backgroundColor = validateColor(assertNodeType(args[1], "raw").string, parser.gullet.macros)
|
144
|
+
}
|
145
|
+
const body = args[2];
|
146
|
+
return {
|
147
|
+
type: "enclose",
|
148
|
+
mode: parser.mode,
|
149
|
+
label: funcName,
|
150
|
+
backgroundColor,
|
151
|
+
borderColor,
|
152
|
+
body
|
153
|
+
};
|
154
|
+
},
|
155
|
+
mathmlBuilder
|
156
|
+
});
|
157
|
+
|
158
|
+
defineFunction({
|
159
|
+
type: "enclose",
|
160
|
+
names: ["\\fbox"],
|
161
|
+
props: {
|
162
|
+
numArgs: 1,
|
163
|
+
argTypes: ["hbox"],
|
164
|
+
allowedInText: true
|
165
|
+
},
|
166
|
+
handler({ parser }, args) {
|
167
|
+
return {
|
168
|
+
type: "enclose",
|
169
|
+
mode: parser.mode,
|
170
|
+
label: "\\fbox",
|
171
|
+
body: args[0]
|
172
|
+
};
|
173
|
+
}
|
174
|
+
});
|
175
|
+
|
176
|
+
defineFunction({
|
177
|
+
type: "enclose",
|
178
|
+
names: ["\\angl", "\\cancel", "\\bcancel", "\\xcancel", "\\sout", "\\overline", "\\underline"],
|
179
|
+
// , "\\phase", "\\longdiv"
|
180
|
+
props: {
|
181
|
+
numArgs: 1
|
182
|
+
},
|
183
|
+
handler({ parser, funcName }, args) {
|
184
|
+
const body = args[0];
|
185
|
+
return {
|
186
|
+
type: "enclose",
|
187
|
+
mode: parser.mode,
|
188
|
+
label: funcName,
|
189
|
+
body
|
190
|
+
};
|
191
|
+
},
|
192
|
+
mathmlBuilder
|
193
|
+
});
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import defineFunction from "../defineFunction";
|
2
|
+
import mathMLTree from "../mathMLTree";
|
3
|
+
|
4
|
+
defineFunction({
|
5
|
+
type: "envTag",
|
6
|
+
names: ["\\env@tag"],
|
7
|
+
props: {
|
8
|
+
numArgs: 1,
|
9
|
+
argTypes: ["math"]
|
10
|
+
},
|
11
|
+
handler({ parser }, args) {
|
12
|
+
return {
|
13
|
+
type: "envTag",
|
14
|
+
mode: parser.mode,
|
15
|
+
body: args[0]
|
16
|
+
};
|
17
|
+
},
|
18
|
+
mathmlBuilder(group, style) {
|
19
|
+
return new mathMLTree.MathNode("mrow");
|
20
|
+
}
|
21
|
+
});
|
22
|
+
|
23
|
+
defineFunction({
|
24
|
+
type: "noTag",
|
25
|
+
names: ["\\env@notag"],
|
26
|
+
props: {
|
27
|
+
numArgs: 0
|
28
|
+
},
|
29
|
+
handler({ parser }) {
|
30
|
+
return {
|
31
|
+
type: "noTag",
|
32
|
+
mode: parser.mode
|
33
|
+
};
|
34
|
+
},
|
35
|
+
mathmlBuilder(group, style) {
|
36
|
+
return new mathMLTree.MathNode("mrow");
|
37
|
+
}
|
38
|
+
});
|
@@ -0,0 +1,59 @@
|
|
1
|
+
import defineFunction from "../defineFunction";
|
2
|
+
import ParseError from "../ParseError";
|
3
|
+
import { assertNodeType } from "../parseNode";
|
4
|
+
import environments from "../environments";
|
5
|
+
|
6
|
+
// Environment delimiters. HTML/MathML rendering is defined in the corresponding
|
7
|
+
// defineEnvironment definitions.
|
8
|
+
defineFunction({
|
9
|
+
type: "environment",
|
10
|
+
names: ["\\begin", "\\end"],
|
11
|
+
props: {
|
12
|
+
numArgs: 1,
|
13
|
+
argTypes: ["text"]
|
14
|
+
},
|
15
|
+
handler({ parser, funcName }, args) {
|
16
|
+
const nameGroup = args[0];
|
17
|
+
if (nameGroup.type !== "ordgroup") {
|
18
|
+
throw new ParseError("Invalid environment name", nameGroup);
|
19
|
+
}
|
20
|
+
let envName = "";
|
21
|
+
for (let i = 0; i < nameGroup.body.length; ++i) {
|
22
|
+
envName += assertNodeType(nameGroup.body[i], "textord").text;
|
23
|
+
}
|
24
|
+
|
25
|
+
if (funcName === "\\begin") {
|
26
|
+
// begin...end is similar to left...right
|
27
|
+
if (!Object.prototype.hasOwnProperty.call(environments, envName )) {
|
28
|
+
throw new ParseError("No such environment: " + envName, nameGroup);
|
29
|
+
}
|
30
|
+
// Build the environment object. Arguments and other information will
|
31
|
+
// be made available to the begin and end methods using properties.
|
32
|
+
const env = environments[envName];
|
33
|
+
const { args, optArgs } = parser.parseArguments("\\begin{" + envName + "}", env);
|
34
|
+
const context = {
|
35
|
+
mode: parser.mode,
|
36
|
+
envName,
|
37
|
+
parser
|
38
|
+
};
|
39
|
+
const result = env.handler(context, args, optArgs);
|
40
|
+
parser.expect("\\end", false);
|
41
|
+
const endNameToken = parser.nextToken;
|
42
|
+
const end = assertNodeType(parser.parseFunction(), "environment");
|
43
|
+
if (end.name !== envName) {
|
44
|
+
throw new ParseError(
|
45
|
+
`Mismatch: \\begin{${envName}} matched by \\end{${end.name}}`,
|
46
|
+
endNameToken
|
47
|
+
);
|
48
|
+
}
|
49
|
+
return result;
|
50
|
+
}
|
51
|
+
|
52
|
+
return {
|
53
|
+
type: "environment",
|
54
|
+
mode: parser.mode,
|
55
|
+
name: envName,
|
56
|
+
nameGroup
|
57
|
+
};
|
58
|
+
}
|
59
|
+
});
|