temml 0.10.21 → 0.10.23
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/README.md +1 -1
- package/dist/Temml-Asana.css +0 -4
- package/dist/Temml-Fira.css +152 -0
- package/dist/Temml-STIX2.css +0 -4
- package/dist/temml.cjs +162 -83
- package/dist/temml.d.ts +1 -1
- package/dist/temml.js +162 -83
- package/dist/temml.min.js +1 -1
- package/dist/temml.mjs +162 -83
- package/dist/temmlPostProcess.js +1 -1
- package/package.json +1 -1
- package/src/Parser.js +8 -1
- package/src/buildMathML.js +7 -4
- package/src/functions/color.js +1 -1
- package/src/functions/delimsizing.js +22 -7
- package/src/functions/font.js +31 -2
- package/src/functions/mclass.js +3 -0
- package/src/functions/reflect.js +24 -0
- package/src/functions/sizing.js +1 -1
- package/src/functions/styling.js +1 -1
- package/src/functions/symbolsOrd.js +0 -2
- package/src/functions.js +1 -0
- package/src/linebreaking.js +3 -2
- package/src/macros.js +49 -53
- package/src/postProcess.js +1 -1
- package/src/replace.js +8 -8
- package/src/symbols.js +7 -1
package/dist/temml.mjs
CHANGED
@@ -934,7 +934,8 @@ defineSymbol(math, textord, "\u2135", "\\aleph", true);
|
|
934
934
|
defineSymbol(math, textord, "\u2200", "\\forall", true);
|
935
935
|
defineSymbol(math, textord, "\u210f", "\\hbar", true);
|
936
936
|
defineSymbol(math, textord, "\u2203", "\\exists", true);
|
937
|
-
|
937
|
+
// ∇ is actually a unary operator, not binary. But this works.
|
938
|
+
defineSymbol(math, bin, "\u2207", "\\nabla", true);
|
938
939
|
defineSymbol(math, textord, "\u266d", "\\flat", true);
|
939
940
|
defineSymbol(math, textord, "\u2113", "\\ell", true);
|
940
941
|
defineSymbol(math, textord, "\u266e", "\\natural", true);
|
@@ -988,6 +989,7 @@ defineSymbol(math, bin, "\u2021", "\\ddagger");
|
|
988
989
|
defineSymbol(math, bin, "\u2240", "\\wr", true);
|
989
990
|
defineSymbol(math, bin, "\u2a3f", "\\amalg");
|
990
991
|
defineSymbol(math, bin, "\u0026", "\\And"); // from amsmath
|
992
|
+
defineSymbol(math, bin, "\u2AFD", "\\sslash", true); // from stmaryrd
|
991
993
|
|
992
994
|
// Arrow Symbols
|
993
995
|
defineSymbol(math, rel, "\u27f5", "\\longleftarrow", true);
|
@@ -1022,6 +1024,7 @@ defineSymbol(math, mathord, "\u2609", "\\astrosun", true);
|
|
1022
1024
|
defineSymbol(math, mathord, "\u263c", "\\sun", true);
|
1023
1025
|
defineSymbol(math, mathord, "\u263e", "\\leftmoon", true);
|
1024
1026
|
defineSymbol(math, mathord, "\u263d", "\\rightmoon", true);
|
1027
|
+
defineSymbol(math, mathord, "\u2295", "\\Earth");
|
1025
1028
|
|
1026
1029
|
// AMS Negated Binary Relations
|
1027
1030
|
defineSymbol(math, rel, "\u226e", "\\nless", true);
|
@@ -1249,6 +1252,8 @@ defineSymbol(math, bin, "\u27d5", "\\leftouterjoin", true);
|
|
1249
1252
|
defineSymbol(math, bin, "\u27d6", "\\rightouterjoin", true);
|
1250
1253
|
defineSymbol(math, bin, "\u27d7", "\\fullouterjoin", true);
|
1251
1254
|
|
1255
|
+
defineSymbol(math, bin, "\u2238", "\\dotminus", true); // stix
|
1256
|
+
|
1252
1257
|
// AMS Arrows
|
1253
1258
|
// Note: unicode-math maps \u21e2 to their own function \rightdasharrow.
|
1254
1259
|
// We'll map it to AMS function \dashrightarrow. It produces the same atom.
|
@@ -1406,6 +1411,7 @@ defineSymbol(math, mathord, "\u2aeb", "\\Bot");
|
|
1406
1411
|
defineSymbol(math, bin, "\u2217", "\u2217", true);
|
1407
1412
|
defineSymbol(math, bin, "+", "+");
|
1408
1413
|
defineSymbol(math, bin, "*", "*");
|
1414
|
+
defineSymbol(math, bin, "\u2044", "/", true);
|
1409
1415
|
defineSymbol(math, bin, "\u2044", "\u2044");
|
1410
1416
|
defineSymbol(math, bin, "\u2212", "-", true);
|
1411
1417
|
defineSymbol(math, bin, "\u22c5", "\\cdot", true);
|
@@ -1862,7 +1868,8 @@ function setLineBreaks(expression, wrapMode, isDisplayMode) {
|
|
1862
1868
|
continue
|
1863
1869
|
}
|
1864
1870
|
block.push(node);
|
1865
|
-
if (node.type && node.type === "mo" && node.children.length === 1
|
1871
|
+
if (node.type && node.type === "mo" && node.children.length === 1 &&
|
1872
|
+
!Object.hasOwn(node.attributes, "movablelimits")) {
|
1866
1873
|
const ch = node.children[0].text;
|
1867
1874
|
if (openDelims.indexOf(ch) > -1) {
|
1868
1875
|
level += 1;
|
@@ -1877,7 +1884,7 @@ function setLineBreaks(expression, wrapMode, isDisplayMode) {
|
|
1877
1884
|
mrows.push(element);
|
1878
1885
|
block = [node];
|
1879
1886
|
}
|
1880
|
-
} else if (level === 0 && wrapMode === "tex") {
|
1887
|
+
} else if (level === 0 && wrapMode === "tex" && ch !== "∇") {
|
1881
1888
|
// Check if the following node is a \nobreak text node, e.g. "~""
|
1882
1889
|
const next = i < expression.length - 1 ? expression[i + 1] : null;
|
1883
1890
|
let glueIsFreeOfNobreak = true;
|
@@ -2015,9 +2022,11 @@ const consolidateText = mrow => {
|
|
2015
2022
|
};
|
2016
2023
|
|
2017
2024
|
const numberRegEx$1 = /^[0-9]$/;
|
2018
|
-
const
|
2019
|
-
return (node.type === "
|
2020
|
-
|
2025
|
+
const isDotOrComma = (node, followingNode) => {
|
2026
|
+
return ((node.type === "textord" && node.text === ".") ||
|
2027
|
+
(node.type === "atom" && node.text === ",")) &&
|
2028
|
+
// Don't consolidate if there is a space after the comma.
|
2029
|
+
node.loc && followingNode.loc && node.loc.end === followingNode.loc.start
|
2021
2030
|
};
|
2022
2031
|
const consolidateNumbers = expression => {
|
2023
2032
|
// Consolidate adjacent numbers. We want to return <mn>1,506.3</mn>,
|
@@ -2040,7 +2049,8 @@ const consolidateNumbers = expression => {
|
|
2040
2049
|
|
2041
2050
|
// Determine if numeral groups are separated by a comma or dot.
|
2042
2051
|
for (let i = nums.length - 1; i > 0; i--) {
|
2043
|
-
if (nums[i - 1].end === nums[i].start - 2 &&
|
2052
|
+
if (nums[i - 1].end === nums[i].start - 2 &&
|
2053
|
+
isDotOrComma(expression[nums[i].start - 1], expression[nums[i].start])) {
|
2044
2054
|
// Merge the two groups.
|
2045
2055
|
nums[i - 1].end = nums[i].end;
|
2046
2056
|
nums.splice(i, 1);
|
@@ -3256,7 +3266,7 @@ defineFunction({
|
|
3256
3266
|
}
|
3257
3267
|
|
3258
3268
|
// Parse out the implicit body that should be colored.
|
3259
|
-
const body = parser.parseExpression(true, breakOnTokenText);
|
3269
|
+
const body = parser.parseExpression(true, breakOnTokenText, true);
|
3260
3270
|
|
3261
3271
|
return {
|
3262
3272
|
type: "color",
|
@@ -3698,17 +3708,13 @@ const sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0];
|
|
3698
3708
|
|
3699
3709
|
// Delimiter functions
|
3700
3710
|
function checkDelimiter(delim, context) {
|
3701
|
-
if (delim.type === "ordgroup" && delim.body.length === 1 && delim.body[0].text === "\u2044") {
|
3702
|
-
// Recover "/" from the zero spacing group. (See macros.js)
|
3703
|
-
delim = { type: "textord", text: "/", mode: "math" };
|
3704
|
-
}
|
3705
3711
|
const symDelim = checkSymbolNodeType(delim);
|
3706
3712
|
if (symDelim && delimiters.includes(symDelim.text)) {
|
3707
3713
|
// If a character is not in the MathML operator dictionary, it will not stretch.
|
3708
3714
|
// Replace such characters w/characters that will stretch.
|
3715
|
+
if (["/", "\u2044"].includes(symDelim.text)) { symDelim.text = "\u2215"; }
|
3709
3716
|
if (["<", "\\lt"].includes(symDelim.text)) { symDelim.text = "⟨"; }
|
3710
3717
|
if ([">", "\\gt"].includes(symDelim.text)) { symDelim.text = "⟩"; }
|
3711
|
-
if (symDelim.text === "/") { symDelim.text = "\u2215"; }
|
3712
3718
|
if (symDelim.text === "\\backslash") { symDelim.text = "\u2216"; }
|
3713
3719
|
return symDelim;
|
3714
3720
|
} else if (symDelim) {
|
@@ -3817,8 +3823,26 @@ defineFunction({
|
|
3817
3823
|
const parser = context.parser;
|
3818
3824
|
// Parse out the implicit body
|
3819
3825
|
++parser.leftrightDepth;
|
3820
|
-
// parseExpression stops before '\\right'
|
3821
|
-
|
3826
|
+
// parseExpression stops before '\\right' or `\\middle`
|
3827
|
+
let body = parser.parseExpression(false, null, true);
|
3828
|
+
let nextToken = parser.fetch();
|
3829
|
+
while (nextToken.text === "\\middle") {
|
3830
|
+
// `\middle`, from the ε-TeX package, ends one group and starts another group.
|
3831
|
+
// We had to parse this expression with `breakOnMiddle` enabled in order
|
3832
|
+
// to get TeX-compliant parsing of \over.
|
3833
|
+
// But we do not want, at this point, to end on \middle, so continue
|
3834
|
+
// to parse until we fetch a `\right`.
|
3835
|
+
parser.consume();
|
3836
|
+
const middle = parser.fetch().text;
|
3837
|
+
if (!symbols.math[middle]) {
|
3838
|
+
throw new ParseError(`Invalid delimiter '${middle}' after '\\middle'`);
|
3839
|
+
}
|
3840
|
+
checkDelimiter({ type: "atom", mode: "math", text: middle }, { funcName: "\\middle" });
|
3841
|
+
body.push({ type: "middle", mode: "math", delim: middle });
|
3842
|
+
parser.consume();
|
3843
|
+
body = body.concat(parser.parseExpression(false, null, true));
|
3844
|
+
nextToken = parser.fetch();
|
3845
|
+
}
|
3822
3846
|
--parser.leftrightDepth;
|
3823
3847
|
// Check the next token
|
3824
3848
|
parser.expect("\\right", false);
|
@@ -5092,6 +5116,21 @@ defineFunction({
|
|
5092
5116
|
}
|
5093
5117
|
});
|
5094
5118
|
|
5119
|
+
const isLongVariableName = (group, font) => {
|
5120
|
+
if (font !== "mathrm" || group.body.type !== "ordgroup" || group.body.body.length === 1) {
|
5121
|
+
return false
|
5122
|
+
}
|
5123
|
+
if (group.body.body[0].type !== "mathord") { return false }
|
5124
|
+
for (let i = 1; i < group.body.body.length; i++) {
|
5125
|
+
const parseNodeType = group.body.body[i].type;
|
5126
|
+
if (!(parseNodeType === "mathord" ||
|
5127
|
+
(parseNodeType === "textord" && !isNaN(group.body.body[i].text)))) {
|
5128
|
+
return false
|
5129
|
+
}
|
5130
|
+
}
|
5131
|
+
return true
|
5132
|
+
};
|
5133
|
+
|
5095
5134
|
const mathmlBuilder$6 = (group, style) => {
|
5096
5135
|
const font = group.font;
|
5097
5136
|
const newStyle = style.withFont(font);
|
@@ -5103,6 +5142,20 @@ const mathmlBuilder$6 = (group, style) => {
|
|
5103
5142
|
return mathGroup
|
5104
5143
|
}
|
5105
5144
|
// Check if it is possible to consolidate elements into a single <mi> element.
|
5145
|
+
if (isLongVariableName(group, font)) {
|
5146
|
+
// This is a \mathrm{…} group. It gets special treatment because symbolsOrd.js
|
5147
|
+
// wraps <mi> elements with <mrow>s to work around a Firefox bug.
|
5148
|
+
const mi = mathGroup.children[0].children[0];
|
5149
|
+
delete mi.attributes.mathvariant;
|
5150
|
+
for (let i = 1; i < mathGroup.children.length; i++) {
|
5151
|
+
mi.children[0].text += mathGroup.children[i].type === "mn"
|
5152
|
+
? mathGroup.children[i].children[0].text
|
5153
|
+
: mathGroup.children[i].children[0].children[0].text;
|
5154
|
+
}
|
5155
|
+
// Wrap in a <mrow> to prevent the same Firefox bug.
|
5156
|
+
const bogus = new mathMLTree.MathNode("mtext", new mathMLTree.TextNode("\u200b"));
|
5157
|
+
return new mathMLTree.MathNode("mrow", [bogus, mi])
|
5158
|
+
}
|
5106
5159
|
let canConsolidate = mathGroup.children[0].type === "mo";
|
5107
5160
|
for (let i = 1; i < mathGroup.children.length; i++) {
|
5108
5161
|
if (mathGroup.children[i].type === "mo" && font === "boldsymbol") {
|
@@ -5193,7 +5246,7 @@ defineFunction({
|
|
5193
5246
|
},
|
5194
5247
|
handler: ({ parser, funcName, breakOnTokenText }, args) => {
|
5195
5248
|
const { mode } = parser;
|
5196
|
-
const body = parser.parseExpression(true, breakOnTokenText);
|
5249
|
+
const body = parser.parseExpression(true, breakOnTokenText, true);
|
5197
5250
|
const fontStyle = `math${funcName.slice(1)}`;
|
5198
5251
|
|
5199
5252
|
return {
|
@@ -6154,6 +6207,9 @@ function mathmlBuilder$3(group, style) {
|
|
6154
6207
|
if (group.isCharacterBox || inner[0].type === "mathord") {
|
6155
6208
|
node = inner[0];
|
6156
6209
|
node.type = "mi";
|
6210
|
+
if (node.children.length === 1 && node.children[0].text && node.children[0].text === "∇") {
|
6211
|
+
node.setAttribute("mathvariant", "normal");
|
6212
|
+
}
|
6157
6213
|
} else {
|
6158
6214
|
node = new mathMLTree.MathNode("mi", inner);
|
6159
6215
|
}
|
@@ -7141,6 +7197,28 @@ defineFunction({
|
|
7141
7197
|
}
|
7142
7198
|
});
|
7143
7199
|
|
7200
|
+
defineFunction({
|
7201
|
+
type: "reflect",
|
7202
|
+
names: ["\\reflectbox"],
|
7203
|
+
props: {
|
7204
|
+
numArgs: 1,
|
7205
|
+
argTypes: ["hbox"],
|
7206
|
+
allowedInText: true
|
7207
|
+
},
|
7208
|
+
handler({ parser }, args) {
|
7209
|
+
return {
|
7210
|
+
type: "reflect",
|
7211
|
+
mode: parser.mode,
|
7212
|
+
body: args[0]
|
7213
|
+
};
|
7214
|
+
},
|
7215
|
+
mathmlBuilder(group, style) {
|
7216
|
+
const node = buildGroup$1(group.body, style);
|
7217
|
+
node.style.transform = "scaleX(-1)";
|
7218
|
+
return node
|
7219
|
+
}
|
7220
|
+
});
|
7221
|
+
|
7144
7222
|
defineFunction({
|
7145
7223
|
type: "internal",
|
7146
7224
|
names: ["\\relax"],
|
@@ -7246,7 +7324,7 @@ defineFunction({
|
|
7246
7324
|
// eslint-disable-next-line no-console
|
7247
7325
|
console.log(`Temml strict-mode warning: Command ${funcName} is invalid in math mode.`);
|
7248
7326
|
}
|
7249
|
-
const body = parser.parseExpression(false, breakOnTokenText);
|
7327
|
+
const body = parser.parseExpression(false, breakOnTokenText, true);
|
7250
7328
|
return {
|
7251
7329
|
type: "sizing",
|
7252
7330
|
mode: parser.mode,
|
@@ -7379,7 +7457,7 @@ defineFunction({
|
|
7379
7457
|
},
|
7380
7458
|
handler({ breakOnTokenText, funcName, parser }, args) {
|
7381
7459
|
// parse out the implicit body
|
7382
|
-
const body = parser.parseExpression(true, breakOnTokenText);
|
7460
|
+
const body = parser.parseExpression(true, breakOnTokenText, true);
|
7383
7461
|
|
7384
7462
|
const scriptLevel = funcName.slice(1, funcName.length - 5);
|
7385
7463
|
return {
|
@@ -7810,22 +7888,22 @@ const offset = Object.freeze({
|
|
7810
7888
|
"sans-serif-bold-italic": ch => { return 0x1D5F5 },
|
7811
7889
|
"monospace": ch => { return 0x1D629 }
|
7812
7890
|
},
|
7813
|
-
upperCaseGreek: { // A-Ω
|
7891
|
+
upperCaseGreek: { // A-Ω
|
7814
7892
|
"normal": ch => { return 0 },
|
7815
|
-
"bold": ch => { return
|
7816
|
-
"italic": ch => { return
|
7893
|
+
"bold": ch => { return 0x1D317 },
|
7894
|
+
"italic": ch => { return 0x1D351 },
|
7817
7895
|
// \boldsymbol actually returns upright bold for upperCaseGreek
|
7818
|
-
"bold-italic": ch => { return
|
7896
|
+
"bold-italic": ch => { return 0x1D317 },
|
7819
7897
|
"script": ch => { return 0 },
|
7820
7898
|
"script-bold": ch => { return 0 },
|
7821
7899
|
"fraktur": ch => { return 0 },
|
7822
7900
|
"fraktur-bold": ch => { return 0 },
|
7823
7901
|
"double-struck": ch => { return 0 },
|
7824
7902
|
// Unicode has no code points for regular-weight san-serif Greek. Use bold.
|
7825
|
-
"sans-serif": ch => { return
|
7826
|
-
"sans-serif-bold": ch => { return
|
7903
|
+
"sans-serif": ch => { return 0x1D3C5 },
|
7904
|
+
"sans-serif-bold": ch => { return 0x1D3C5 },
|
7827
7905
|
"sans-serif-italic": ch => { return 0 },
|
7828
|
-
"sans-serif-bold-italic": ch => { return
|
7906
|
+
"sans-serif-bold-italic": ch => { return 0x1D3FF },
|
7829
7907
|
"monospace": ch => { return 0 }
|
7830
7908
|
},
|
7831
7909
|
lowerCaseGreek: { // α-ω
|
@@ -7885,7 +7963,7 @@ const variantChar = (ch, variant) => {
|
|
7885
7963
|
? "upperCaseLatin"
|
7886
7964
|
: 0x60 < codePoint && codePoint < 0x7b
|
7887
7965
|
? "lowerCaseLatin"
|
7888
|
-
: (0x390 < codePoint && codePoint < 0x3AA)
|
7966
|
+
: (0x390 < codePoint && codePoint < 0x3AA)
|
7889
7967
|
? "upperCaseGreek"
|
7890
7968
|
: 0x3B0 < codePoint && codePoint < 0x3CA || ch === "\u03d5"
|
7891
7969
|
? "lowerCaseGreek"
|
@@ -8014,8 +8092,6 @@ defineFunctionBuilders({
|
|
8014
8092
|
node = new mathMLTree.MathNode("mi", [text]);
|
8015
8093
|
if (text.text === origText && latinRegEx.test(origText)) {
|
8016
8094
|
node.setAttribute("mathvariant", "italic");
|
8017
|
-
} else if (text.text === "∇" && variant === "normal") {
|
8018
|
-
node.setAttribute("mathvariant", "normal");
|
8019
8095
|
}
|
8020
8096
|
}
|
8021
8097
|
return node
|
@@ -8652,6 +8728,24 @@ defineMacro("\\char", function(context) {
|
|
8652
8728
|
return `\\@char{${number}}`;
|
8653
8729
|
});
|
8654
8730
|
|
8731
|
+
function recreateArgStr(context) {
|
8732
|
+
// Recreate the macro's original argument string from the array of parse tokens.
|
8733
|
+
const tokens = context.consumeArgs(1)[0];
|
8734
|
+
let str = "";
|
8735
|
+
let expectedLoc = tokens[tokens.length - 1].loc.start;
|
8736
|
+
for (let i = tokens.length - 1; i >= 0; i--) {
|
8737
|
+
const actualLoc = tokens[i].loc.start;
|
8738
|
+
if (actualLoc > expectedLoc) {
|
8739
|
+
// context.consumeArgs has eaten a space.
|
8740
|
+
str += " ";
|
8741
|
+
expectedLoc = actualLoc;
|
8742
|
+
}
|
8743
|
+
str += tokens[i].text;
|
8744
|
+
expectedLoc += tokens[i].text.length;
|
8745
|
+
}
|
8746
|
+
return str
|
8747
|
+
}
|
8748
|
+
|
8655
8749
|
// The Latin Modern font renders <mi>√</mi> at the wrong vertical alignment.
|
8656
8750
|
// This macro provides a better rendering.
|
8657
8751
|
defineMacro("\\surd", '\\sqrt{\\vphantom{|}}');
|
@@ -8659,10 +8753,6 @@ defineMacro("\\surd", '\\sqrt{\\vphantom{|}}');
|
|
8659
8753
|
// See comment for \oplus in symbols.js.
|
8660
8754
|
defineMacro("\u2295", "\\oplus");
|
8661
8755
|
|
8662
|
-
// Per TeXbook p.122, "/" gets zero operator spacing.
|
8663
|
-
// And MDN recommends using U+2044 instead of / for inline
|
8664
|
-
defineMacro("/", "{\u2044}");
|
8665
|
-
|
8666
8756
|
// Since Temml has no \par, ignore \long.
|
8667
8757
|
defineMacro("\\long", "");
|
8668
8758
|
|
@@ -9040,6 +9130,11 @@ defineMacro("\\argmin", "\\DOTSB\\operatorname*{arg\\,min}");
|
|
9040
9130
|
defineMacro("\\argmax", "\\DOTSB\\operatorname*{arg\\,max}");
|
9041
9131
|
defineMacro("\\plim", "\\DOTSB\\operatorname*{plim}");
|
9042
9132
|
|
9133
|
+
//////////////////////////////////////////////////////////////////////
|
9134
|
+
// MnSymbol.sty
|
9135
|
+
|
9136
|
+
defineMacro("\\leftmodels", "\\mathop{\\reflectbox{$\\models$}}");
|
9137
|
+
|
9043
9138
|
//////////////////////////////////////////////////////////////////////
|
9044
9139
|
// braket.sty
|
9045
9140
|
// http://ctan.math.washington.edu/tex-archive/macros/latex/contrib/braket/braket.pdf
|
@@ -9049,56 +9144,33 @@ defineMacro("\\ket", "\\mathinner{|{#1}\\rangle}");
|
|
9049
9144
|
defineMacro("\\braket", "\\mathinner{\\langle{#1}\\rangle}");
|
9050
9145
|
defineMacro("\\Bra", "\\left\\langle#1\\right|");
|
9051
9146
|
defineMacro("\\Ket", "\\left|#1\\right\\rangle");
|
9052
|
-
|
9053
|
-
|
9054
|
-
const
|
9055
|
-
const
|
9056
|
-
|
9057
|
-
const oldMiddle = context.macros.get("|");
|
9058
|
-
const oldMiddleDouble = context.macros.get("\\|");
|
9059
|
-
context.macros.beginGroup();
|
9060
|
-
const midMacro = (double) => (context) => {
|
9061
|
-
if (one) {
|
9062
|
-
// Only modify the first instance of | or \|
|
9063
|
-
context.macros.set("|", oldMiddle);
|
9064
|
-
if (middleDouble.length) {
|
9065
|
-
context.macros.set("\\|", oldMiddleDouble);
|
9066
|
-
}
|
9067
|
-
}
|
9068
|
-
let doubled = double;
|
9069
|
-
if (!double && middleDouble.length) {
|
9070
|
-
// Mimic \@ifnextchar
|
9071
|
-
const nextToken = context.future();
|
9072
|
-
if (nextToken.text === "|") {
|
9073
|
-
context.popToken();
|
9074
|
-
doubled = true;
|
9075
|
-
}
|
9076
|
-
}
|
9077
|
-
return {
|
9078
|
-
tokens: doubled ? middleDouble : middle,
|
9079
|
-
numArgs: 0
|
9080
|
-
};
|
9081
|
-
};
|
9082
|
-
context.macros.set("|", midMacro(false));
|
9083
|
-
if (middleDouble.length) {
|
9084
|
-
context.macros.set("\\|", midMacro(true));
|
9085
|
-
}
|
9086
|
-
const arg = context.consumeArg().tokens;
|
9087
|
-
const expanded = context.expandTokens([...right, ...arg, ...left]); // reversed
|
9088
|
-
context.macros.endGroup();
|
9089
|
-
return {
|
9090
|
-
tokens: expanded.reverse(),
|
9091
|
-
numArgs: 0
|
9092
|
-
};
|
9147
|
+
// A helper for \Braket and \Set
|
9148
|
+
const replaceVert = (argStr, match) => {
|
9149
|
+
const ch = match[0] === "|" ? "\\vert" : "\\Vert";
|
9150
|
+
const replaceStr = `}\\,\\middle${ch}\\,{`;
|
9151
|
+
return argStr.slice(0, match.index) + replaceStr + argStr.slice(match.index + match[0].length)
|
9093
9152
|
};
|
9094
|
-
defineMacro("\\
|
9095
|
-
|
9096
|
-
|
9097
|
-
|
9098
|
-
|
9099
|
-
|
9100
|
-
|
9101
|
-
|
9153
|
+
defineMacro("\\Braket", function(context) {
|
9154
|
+
let argStr = recreateArgStr(context);
|
9155
|
+
const regEx = /\|\||\||\\\|/g;
|
9156
|
+
let match;
|
9157
|
+
while ((match = regEx.exec(argStr)) !== null) {
|
9158
|
+
argStr = replaceVert(argStr, match);
|
9159
|
+
}
|
9160
|
+
return "\\left\\langle{" + argStr + "}\\right\\rangle"
|
9161
|
+
});
|
9162
|
+
defineMacro("\\Set", function(context) {
|
9163
|
+
let argStr = recreateArgStr(context);
|
9164
|
+
const match = /\|\||\||\\\|/.exec(argStr);
|
9165
|
+
if (match) {
|
9166
|
+
argStr = replaceVert(argStr, match);
|
9167
|
+
}
|
9168
|
+
return "\\left\\{\\:{" + argStr + "}\\:\\right\\}"
|
9169
|
+
});
|
9170
|
+
defineMacro("\\set", function(context) {
|
9171
|
+
const argStr = recreateArgStr(context);
|
9172
|
+
return "\\{{" + argStr.replace(/\|/, "}\\mid{") + "}\\}"
|
9173
|
+
});
|
9102
9174
|
|
9103
9175
|
//////////////////////////////////////////////////////////////////////
|
9104
9176
|
// actuarialangle.dtx
|
@@ -12147,8 +12219,12 @@ class Parser {
|
|
12147
12219
|
* `breakOnTokenText`: The text of the token that the expression should end
|
12148
12220
|
* with, or `null` if something else should end the
|
12149
12221
|
* expression.
|
12222
|
+
*
|
12223
|
+
* `breakOnMiddle`: \color, \over, and old styling functions work on an implicit group.
|
12224
|
+
* These groups end just before the usual tokens, but they also
|
12225
|
+
* end just before `\middle`.
|
12150
12226
|
*/
|
12151
|
-
parseExpression(breakOnInfix, breakOnTokenText) {
|
12227
|
+
parseExpression(breakOnInfix, breakOnTokenText, breakOnMiddle) {
|
12152
12228
|
const body = [];
|
12153
12229
|
// Keep adding atoms to the body until we can't parse any more atoms (either
|
12154
12230
|
// we reached the end, a }, or a \right)
|
@@ -12164,6 +12240,9 @@ class Parser {
|
|
12164
12240
|
if (breakOnTokenText && lex.text === breakOnTokenText) {
|
12165
12241
|
break;
|
12166
12242
|
}
|
12243
|
+
if (breakOnMiddle && lex.text === "\\middle") {
|
12244
|
+
break
|
12245
|
+
}
|
12167
12246
|
if (breakOnInfix && functions[lex.text] && functions[lex.text].infix) {
|
12168
12247
|
break;
|
12169
12248
|
}
|
@@ -13142,7 +13221,7 @@ class Style {
|
|
13142
13221
|
* https://mit-license.org/
|
13143
13222
|
*/
|
13144
13223
|
|
13145
|
-
const version = "0.10.
|
13224
|
+
const version = "0.10.23";
|
13146
13225
|
|
13147
13226
|
function postProcess(block) {
|
13148
13227
|
const labelMap = {};
|
package/dist/temmlPostProcess.js
CHANGED
package/package.json
CHANGED
package/src/Parser.js
CHANGED
@@ -179,8 +179,12 @@ export default class Parser {
|
|
179
179
|
* `breakOnTokenText`: The text of the token that the expression should end
|
180
180
|
* with, or `null` if something else should end the
|
181
181
|
* expression.
|
182
|
+
*
|
183
|
+
* `breakOnMiddle`: \color, \over, and old styling functions work on an implicit group.
|
184
|
+
* These groups end just before the usual tokens, but they also
|
185
|
+
* end just before `\middle`.
|
182
186
|
*/
|
183
|
-
parseExpression(breakOnInfix, breakOnTokenText) {
|
187
|
+
parseExpression(breakOnInfix, breakOnTokenText, breakOnMiddle) {
|
184
188
|
const body = [];
|
185
189
|
// Keep adding atoms to the body until we can't parse any more atoms (either
|
186
190
|
// we reached the end, a }, or a \right)
|
@@ -196,6 +200,9 @@ export default class Parser {
|
|
196
200
|
if (breakOnTokenText && lex.text === breakOnTokenText) {
|
197
201
|
break;
|
198
202
|
}
|
203
|
+
if (breakOnMiddle && lex.text === "\\middle") {
|
204
|
+
break
|
205
|
+
}
|
199
206
|
if (breakOnInfix && functions[lex.text] && functions[lex.text].infix) {
|
200
207
|
break;
|
201
208
|
}
|
package/src/buildMathML.js
CHANGED
@@ -80,9 +80,11 @@ export const consolidateText = mrow => {
|
|
80
80
|
}
|
81
81
|
|
82
82
|
const numberRegEx = /^[0-9]$/
|
83
|
-
const
|
84
|
-
return (node.type === "
|
85
|
-
|
83
|
+
const isDotOrComma = (node, followingNode) => {
|
84
|
+
return ((node.type === "textord" && node.text === ".") ||
|
85
|
+
(node.type === "atom" && node.text === ",")) &&
|
86
|
+
// Don't consolidate if there is a space after the comma.
|
87
|
+
node.loc && followingNode.loc && node.loc.end === followingNode.loc.start
|
86
88
|
}
|
87
89
|
const consolidateNumbers = expression => {
|
88
90
|
// Consolidate adjacent numbers. We want to return <mn>1,506.3</mn>,
|
@@ -105,7 +107,8 @@ const consolidateNumbers = expression => {
|
|
105
107
|
|
106
108
|
// Determine if numeral groups are separated by a comma or dot.
|
107
109
|
for (let i = nums.length - 1; i > 0; i--) {
|
108
|
-
if (nums[i - 1].end === nums[i].start - 2 &&
|
110
|
+
if (nums[i - 1].end === nums[i].start - 2 &&
|
111
|
+
isDotOrComma(expression[nums[i].start - 1], expression[nums[i].start])) {
|
109
112
|
// Merge the two groups.
|
110
113
|
nums[i - 1].end = nums[i].end
|
111
114
|
nums.splice(i, 1)
|
package/src/functions/color.js
CHANGED
@@ -212,7 +212,7 @@ defineFunction({
|
|
212
212
|
}
|
213
213
|
|
214
214
|
// Parse out the implicit body that should be colored.
|
215
|
-
const body = parser.parseExpression(true, breakOnTokenText)
|
215
|
+
const body = parser.parseExpression(true, breakOnTokenText, true)
|
216
216
|
|
217
217
|
return {
|
218
218
|
type: "color",
|
@@ -4,6 +4,7 @@ import ParseError from "../ParseError";
|
|
4
4
|
import { assertNodeType, checkSymbolNodeType } from "../parseNode";
|
5
5
|
|
6
6
|
import * as mml from "../buildMathML";
|
7
|
+
import symbols from "../symbols";
|
7
8
|
|
8
9
|
// Extra data needed for the delimiter handler down below
|
9
10
|
export const delimiterSizes = {
|
@@ -113,17 +114,13 @@ const sizeToMaxHeight = [0, 1.2, 1.8, 2.4, 3.0];
|
|
113
114
|
|
114
115
|
// Delimiter functions
|
115
116
|
function checkDelimiter(delim, context) {
|
116
|
-
if (delim.type === "ordgroup" && delim.body.length === 1 && delim.body[0].text === "\u2044") {
|
117
|
-
// Recover "/" from the zero spacing group. (See macros.js)
|
118
|
-
delim = { type: "textord", text: "/", mode: "math" }
|
119
|
-
}
|
120
117
|
const symDelim = checkSymbolNodeType(delim)
|
121
118
|
if (symDelim && delimiters.includes(symDelim.text)) {
|
122
119
|
// If a character is not in the MathML operator dictionary, it will not stretch.
|
123
120
|
// Replace such characters w/characters that will stretch.
|
121
|
+
if (["/", "\u2044"].includes(symDelim.text)) { symDelim.text = "\u2215" }
|
124
122
|
if (["<", "\\lt"].includes(symDelim.text)) { symDelim.text = "⟨" }
|
125
123
|
if ([">", "\\gt"].includes(symDelim.text)) { symDelim.text = "⟩" }
|
126
|
-
if (symDelim.text === "/") { symDelim.text = "\u2215" }
|
127
124
|
if (symDelim.text === "\\backslash") { symDelim.text = "\u2216" }
|
128
125
|
return symDelim;
|
129
126
|
} else if (symDelim) {
|
@@ -232,8 +229,26 @@ defineFunction({
|
|
232
229
|
const parser = context.parser;
|
233
230
|
// Parse out the implicit body
|
234
231
|
++parser.leftrightDepth;
|
235
|
-
// parseExpression stops before '\\right'
|
236
|
-
|
232
|
+
// parseExpression stops before '\\right' or `\\middle`
|
233
|
+
let body = parser.parseExpression(false, null, true)
|
234
|
+
let nextToken = parser.fetch()
|
235
|
+
while (nextToken.text === "\\middle") {
|
236
|
+
// `\middle`, from the ε-TeX package, ends one group and starts another group.
|
237
|
+
// We had to parse this expression with `breakOnMiddle` enabled in order
|
238
|
+
// to get TeX-compliant parsing of \over.
|
239
|
+
// But we do not want, at this point, to end on \middle, so continue
|
240
|
+
// to parse until we fetch a `\right`.
|
241
|
+
parser.consume()
|
242
|
+
const middle = parser.fetch().text
|
243
|
+
if (!symbols.math[middle]) {
|
244
|
+
throw new ParseError(`Invalid delimiter '${middle}' after '\\middle'`);
|
245
|
+
}
|
246
|
+
checkDelimiter({ type: "atom", mode: "math", text: middle }, { funcName: "\\middle" })
|
247
|
+
body.push({ type: "middle", mode: "math", delim: middle })
|
248
|
+
parser.consume()
|
249
|
+
body = body.concat(parser.parseExpression(false, null, true))
|
250
|
+
nextToken = parser.fetch()
|
251
|
+
}
|
237
252
|
--parser.leftrightDepth;
|
238
253
|
// Check the next token
|
239
254
|
parser.expect("\\right", false);
|
package/src/functions/font.js
CHANGED
@@ -2,6 +2,21 @@ import defineFunction, { normalizeArgument } from "../defineFunction"
|
|
2
2
|
import * as mml from "../buildMathML"
|
3
3
|
import mathMLTree from "../mathMLTree"
|
4
4
|
|
5
|
+
const isLongVariableName = (group, font) => {
|
6
|
+
if (font !== "mathrm" || group.body.type !== "ordgroup" || group.body.body.length === 1) {
|
7
|
+
return false
|
8
|
+
}
|
9
|
+
if (group.body.body[0].type !== "mathord") { return false }
|
10
|
+
for (let i = 1; i < group.body.body.length; i++) {
|
11
|
+
const parseNodeType = group.body.body[i].type
|
12
|
+
if (!(parseNodeType === "mathord" ||
|
13
|
+
(parseNodeType === "textord" && !isNaN(group.body.body[i].text)))) {
|
14
|
+
return false
|
15
|
+
}
|
16
|
+
}
|
17
|
+
return true
|
18
|
+
}
|
19
|
+
|
5
20
|
const mathmlBuilder = (group, style) => {
|
6
21
|
const font = group.font
|
7
22
|
const newStyle = style.withFont(font)
|
@@ -13,6 +28,20 @@ const mathmlBuilder = (group, style) => {
|
|
13
28
|
return mathGroup
|
14
29
|
}
|
15
30
|
// Check if it is possible to consolidate elements into a single <mi> element.
|
31
|
+
if (isLongVariableName(group, font)) {
|
32
|
+
// This is a \mathrm{…} group. It gets special treatment because symbolsOrd.js
|
33
|
+
// wraps <mi> elements with <mrow>s to work around a Firefox bug.
|
34
|
+
const mi = mathGroup.children[0].children[0];
|
35
|
+
delete mi.attributes.mathvariant
|
36
|
+
for (let i = 1; i < mathGroup.children.length; i++) {
|
37
|
+
mi.children[0].text += mathGroup.children[i].type === "mn"
|
38
|
+
? mathGroup.children[i].children[0].text
|
39
|
+
: mathGroup.children[i].children[0].children[0].text
|
40
|
+
}
|
41
|
+
// Wrap in a <mrow> to prevent the same Firefox bug.
|
42
|
+
const bogus = new mathMLTree.MathNode("mtext", new mathMLTree.TextNode("\u200b"))
|
43
|
+
return new mathMLTree.MathNode("mrow", [bogus, mi])
|
44
|
+
}
|
16
45
|
let canConsolidate = mathGroup.children[0].type === "mo"
|
17
46
|
for (let i = 1; i < mathGroup.children.length; i++) {
|
18
47
|
if (mathGroup.children[i].type === "mo" && font === "boldsymbol") {
|
@@ -25,7 +54,7 @@ const mathmlBuilder = (group, style) => {
|
|
25
54
|
}
|
26
55
|
if (!canConsolidate) { return mathGroup }
|
27
56
|
// Consolidate the <mi> elements.
|
28
|
-
const mi = mathGroup.children[0]
|
57
|
+
const mi = mathGroup.children[0];
|
29
58
|
for (let i = 1; i < mathGroup.children.length; i++) {
|
30
59
|
mi.children.push(mathGroup.children[i].children[0])
|
31
60
|
}
|
@@ -103,7 +132,7 @@ defineFunction({
|
|
103
132
|
},
|
104
133
|
handler: ({ parser, funcName, breakOnTokenText }, args) => {
|
105
134
|
const { mode } = parser;
|
106
|
-
const body = parser.parseExpression(true, breakOnTokenText);
|
135
|
+
const body = parser.parseExpression(true, breakOnTokenText, true);
|
107
136
|
const fontStyle = `math${funcName.slice(1)}`;
|
108
137
|
|
109
138
|
return {
|
package/src/functions/mclass.js
CHANGED
@@ -23,6 +23,9 @@ function mathmlBuilder(group, style) {
|
|
23
23
|
if (group.isCharacterBox || inner[0].type === "mathord") {
|
24
24
|
node = inner[0];
|
25
25
|
node.type = "mi";
|
26
|
+
if (node.children.length === 1 && node.children[0].text && node.children[0].text === "∇") {
|
27
|
+
node.setAttribute("mathvariant", "normal")
|
28
|
+
}
|
26
29
|
} else {
|
27
30
|
node = new mathMLTree.MathNode("mi", inner);
|
28
31
|
}
|