temml 0.12.2 → 0.13.2
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 +3 -4
- package/contrib/mhchem/mhchem.min.js +1 -1
- package/dist/Temml-Asana.css +11 -13
- package/dist/Temml-Latin-Modern.css +11 -13
- package/dist/Temml-Libertinus.css +11 -13
- package/dist/Temml-Local.css +11 -13
- package/dist/Temml-NotoSans.css +11 -13
- package/dist/Temml-STIX2.css +11 -13
- package/dist/temml.cjs +227 -116
- package/dist/temml.js +227 -116
- package/dist/temml.min.js +1 -1
- package/dist/temml.mjs +227 -116
- package/dist/temmlPostProcess.js +1 -1
- package/package.json +2 -2
- package/src/Parser.js +11 -4
- package/src/Settings.js +1 -0
- package/src/functions/cancelto.js +2 -0
- package/src/functions/color.js +1 -1
- package/src/functions/{delimsizing.js → delimiter.js} +132 -42
- package/src/functions/enclose.js +1 -1
- package/src/functions/genfrac.js +32 -45
- package/src/functions/mclass.js +10 -2
- package/src/functions/op.js +1 -1
- package/src/functions/operatorname.js +9 -1
- package/src/functions/symbolsOrd.js +2 -2
- package/src/functions.js +1 -1
- package/src/linebreaking.js +3 -10
- package/src/macros.js +2 -2
- package/src/parseNode.js +1 -1
- package/src/parseTree.js +20 -4
- package/src/postProcess.js +1 -1
- package/src/symbols.js +2 -3
package/dist/temml.cjs
CHANGED
|
@@ -215,6 +215,7 @@ class Settings {
|
|
|
215
215
|
: [Infinity, Infinity]
|
|
216
216
|
);
|
|
217
217
|
this.maxExpand = Math.max(0, deflt(options.maxExpand, 1000)); // number
|
|
218
|
+
this.wrapDelimiterPairs = true; // boolean
|
|
218
219
|
}
|
|
219
220
|
|
|
220
221
|
/**
|
|
@@ -996,8 +997,7 @@ defineSymbol(math, textord, "\u2135", "\\aleph", true);
|
|
|
996
997
|
defineSymbol(math, textord, "\u2200", "\\forall", true);
|
|
997
998
|
defineSymbol(math, textord, "\u210f", "\\hbar", true);
|
|
998
999
|
defineSymbol(math, textord, "\u2203", "\\exists", true);
|
|
999
|
-
|
|
1000
|
-
defineSymbol(math, bin, "\u2207", "\\nabla", true);
|
|
1000
|
+
defineSymbol(math, open, "\u2207", "\\nabla", true);
|
|
1001
1001
|
defineSymbol(math, textord, "\u266d", "\\flat", true);
|
|
1002
1002
|
defineSymbol(math, textord, "\u2113", "\\ell", true);
|
|
1003
1003
|
defineSymbol(math, textord, "\u266e", "\\natural", true);
|
|
@@ -1090,7 +1090,7 @@ defineSymbol(math, mathord, "\u2295", "\\Earth");
|
|
|
1090
1090
|
|
|
1091
1091
|
// AMS Negated Binary Relations
|
|
1092
1092
|
defineSymbol(math, rel, "\u226e", "\\nless", true);
|
|
1093
|
-
// Symbol names
|
|
1093
|
+
// Symbol names preceded by "@" each have a corresponding macro.
|
|
1094
1094
|
defineSymbol(math, rel, "\u2a87", "\\lneq", true);
|
|
1095
1095
|
defineSymbol(math, rel, "\u2268", "\\lneqq", true);
|
|
1096
1096
|
defineSymbol(math, rel, "\u2268\ufe00", "\\lvertneqq");
|
|
@@ -2001,16 +2001,12 @@ for (let i = 0; i < 10; i++) {
|
|
|
2001
2001
|
* much of this module.
|
|
2002
2002
|
*/
|
|
2003
2003
|
|
|
2004
|
-
const openDelims = "([{⌊⌈⟨⟮⎰⟦⦃";
|
|
2005
|
-
const closeDelims = ")]}⌋⌉⟩⟯⎱⟦⦄";
|
|
2006
|
-
|
|
2007
2004
|
function setLineBreaks(expression, wrapMode, isDisplayMode) {
|
|
2008
2005
|
const mtrs = [];
|
|
2009
2006
|
let mrows = [];
|
|
2010
2007
|
let block = [];
|
|
2011
2008
|
let numTopLevelEquals = 0;
|
|
2012
2009
|
let i = 0;
|
|
2013
|
-
let level = 0;
|
|
2014
2010
|
while (i < expression.length) {
|
|
2015
2011
|
while (expression[i] instanceof DocumentFragment) {
|
|
2016
2012
|
expression.splice(i, 1, ...expression[i].children); // Expand the fragment.
|
|
@@ -2033,13 +2029,10 @@ function setLineBreaks(expression, wrapMode, isDisplayMode) {
|
|
|
2033
2029
|
}
|
|
2034
2030
|
block.push(node);
|
|
2035
2031
|
if (node.type && node.type === "mo" && node.children.length === 1 &&
|
|
2032
|
+
!(node.attributes.form && node.attributes.form === "prefix") && // unary operators
|
|
2036
2033
|
!Object.prototype.hasOwnProperty.call(node.attributes, "movablelimits")) {
|
|
2037
2034
|
const ch = node.children[0].text;
|
|
2038
|
-
if (
|
|
2039
|
-
level += 1;
|
|
2040
|
-
} else if (closeDelims.indexOf(ch) > -1) {
|
|
2041
|
-
level -= 1;
|
|
2042
|
-
} else if (level === 0 && wrapMode === "=" && ch === "=") {
|
|
2035
|
+
if (wrapMode === "=" && ch === "=") {
|
|
2043
2036
|
numTopLevelEquals += 1;
|
|
2044
2037
|
if (numTopLevelEquals > 1) {
|
|
2045
2038
|
block.pop();
|
|
@@ -2048,7 +2041,7 @@ function setLineBreaks(expression, wrapMode, isDisplayMode) {
|
|
|
2048
2041
|
mrows.push(element);
|
|
2049
2042
|
block = [node];
|
|
2050
2043
|
}
|
|
2051
|
-
} else if (
|
|
2044
|
+
} else if (wrapMode === "tex") {
|
|
2052
2045
|
// Check if the following node is a \nobreak text node, e.g. "~""
|
|
2053
2046
|
const next = i < expression.length - 1 ? expression[i + 1] : null;
|
|
2054
2047
|
let glueIsFreeOfNobreak = true;
|
|
@@ -3070,7 +3063,7 @@ function assertSymbolNodeType(node) {
|
|
|
3070
3063
|
* returns null.
|
|
3071
3064
|
*/
|
|
3072
3065
|
function checkSymbolNodeType(node) {
|
|
3073
|
-
if (node && (node.type === "atom" ||
|
|
3066
|
+
if (node && (node.type === "atom" || node.type === "delimiter" ||
|
|
3074
3067
|
Object.prototype.hasOwnProperty.call(NON_ATOMS, node.type))) {
|
|
3075
3068
|
return node;
|
|
3076
3069
|
}
|
|
@@ -3876,7 +3869,6 @@ const dotsByToken = {
|
|
|
3876
3869
|
"\\iint": "\\dotsi",
|
|
3877
3870
|
"\\iiint": "\\dotsi",
|
|
3878
3871
|
"\\iiiint": "\\dotsi",
|
|
3879
|
-
"\\idotsint": "\\dotsi",
|
|
3880
3872
|
// Symbols whose definition starts with \DOTSX:
|
|
3881
3873
|
"\\DOTSX": "\\dotsx"
|
|
3882
3874
|
};
|
|
@@ -3958,7 +3950,7 @@ defineMacro("\\cdots", function(context) {
|
|
|
3958
3950
|
defineMacro("\\dotsb", "\\cdots");
|
|
3959
3951
|
defineMacro("\\dotsm", "\\cdots");
|
|
3960
3952
|
defineMacro("\\dotsi", "\\!\\cdots");
|
|
3961
|
-
defineMacro("\\idotsint", "\\
|
|
3953
|
+
defineMacro("\\idotsint", "\\int\\!\\cdots\\!\\int");
|
|
3962
3954
|
// amsmath doesn't actually define \dotsx, but \dots followed by a macro
|
|
3963
3955
|
// starting with \DOTSX implies \dotso, and then \extra@ detects this case
|
|
3964
3956
|
// and forces the added `\,`.
|
|
@@ -4253,6 +4245,7 @@ defineMacro("\\upomega", "\\up@greek{\\omega}");
|
|
|
4253
4245
|
// cmll package
|
|
4254
4246
|
defineMacro("\\invamp", '\\mathbin{\\char"214b}');
|
|
4255
4247
|
defineMacro("\\parr", '\\mathbin{\\char"214b}');
|
|
4248
|
+
defineMacro("\\upand", '\\mathbin{\\char"214b}'); // STIX package
|
|
4256
4249
|
defineMacro("\\with", '\\mathbin{\\char"26}');
|
|
4257
4250
|
defineMacro("\\multimapinv", '\\mathrel{\\char"27dc}');
|
|
4258
4251
|
defineMacro("\\multimapboth", '\\mathrel{\\char"29df}');
|
|
@@ -7224,6 +7217,7 @@ defineFunction({
|
|
|
7224
7217
|
// That way, the arrow will be an overlay on the content.
|
|
7225
7218
|
const phantom = new MathNode("mphantom", [buildGroup$1(group.body, style)]);
|
|
7226
7219
|
const arrow = new MathNode("mrow", [phantom], ["tml-cancelto"]);
|
|
7220
|
+
arrow.style.color = style.color;
|
|
7227
7221
|
if (group.isCharacterBox && smalls.indexOf(group.body.body[0].text) > -1) {
|
|
7228
7222
|
arrow.style.left = "0.1em";
|
|
7229
7223
|
arrow.style.width = "90%";
|
|
@@ -7255,6 +7249,7 @@ defineFunction({
|
|
|
7255
7249
|
dummyNode = new MathNode("mphantom", [zeroWidthNode]); // Hide it.
|
|
7256
7250
|
}
|
|
7257
7251
|
const toNode = buildGroup$1(group.to, style);
|
|
7252
|
+
toNode.style.color = style.color;
|
|
7258
7253
|
const zeroWidthToNode = new MathNode("mpadded", [toNode]);
|
|
7259
7254
|
if (!group.isCharacterBox || /[f∫∑]/.test(group.body.body[0].text)) {
|
|
7260
7255
|
const w = new MathNode("mspace", []);
|
|
@@ -7313,7 +7308,7 @@ const toHex = num => {
|
|
|
7313
7308
|
|
|
7314
7309
|
// Colors from Tables 4.1 and 4.2 of the xcolor package.
|
|
7315
7310
|
// Table 4.1 (lower case) RGB values are taken from chroma and xcolor.dtx.
|
|
7316
|
-
// Table 4.2 (
|
|
7311
|
+
// Table 4.2 (Capitalized) values were sampled, because Chroma contains a unreliable
|
|
7317
7312
|
// conversion from cmyk to RGB. See https://tex.stackexchange.com/a/537274.
|
|
7318
7313
|
const xcolors = JSON.parse(`{
|
|
7319
7314
|
"Apricot": "#ffb484",
|
|
@@ -7872,7 +7867,41 @@ const delimiterSizes = {
|
|
|
7872
7867
|
"\\Bigg": { mclass: "mord", size: 4 }
|
|
7873
7868
|
};
|
|
7874
7869
|
|
|
7875
|
-
const
|
|
7870
|
+
const leftToRight = {
|
|
7871
|
+
"(": ")",
|
|
7872
|
+
"\\lparen": "\\rparen",
|
|
7873
|
+
"[": "]",
|
|
7874
|
+
"\\lbrack": "\\rbrack",
|
|
7875
|
+
"\\{": "\\}",
|
|
7876
|
+
"\\lbrace": "\\rbrace",
|
|
7877
|
+
"⦇": "⦈",
|
|
7878
|
+
"\\llparenthesis": "\\rrparenthesis",
|
|
7879
|
+
"\\lfloor": "\\rfloor",
|
|
7880
|
+
"\u230a": "\u230b",
|
|
7881
|
+
"\\lceil": "\\rceil",
|
|
7882
|
+
"\u2308": "\u2309",
|
|
7883
|
+
"\\langle": "\\rangle",
|
|
7884
|
+
"\u27e8": "\u27e9",
|
|
7885
|
+
"\\lAngle": "\\rAngle",
|
|
7886
|
+
"\u27ea": "\u27eb",
|
|
7887
|
+
"\\llangle": "\\rrangle",
|
|
7888
|
+
"⦉": "⦊",
|
|
7889
|
+
"\\lvert": "\\rvert",
|
|
7890
|
+
"\\lVert": "\\rVert",
|
|
7891
|
+
"\\lgroup": "\\rgroup",
|
|
7892
|
+
"\u27ee": "\u27ef",
|
|
7893
|
+
"\\lmoustache": "\\rmoustache",
|
|
7894
|
+
"\u23b0": "\u23b1",
|
|
7895
|
+
"\\llbracket": "\\rrbracket",
|
|
7896
|
+
"\u27e6": "\u27e7",
|
|
7897
|
+
"\\lBrace": "\\rBrace",
|
|
7898
|
+
"\u2983": "\u2984"
|
|
7899
|
+
};
|
|
7900
|
+
|
|
7901
|
+
const leftDelimiterNames = new Set(Object.keys(leftToRight));
|
|
7902
|
+
new Set(Object.values(leftToRight));
|
|
7903
|
+
|
|
7904
|
+
const delimiters = new Set([
|
|
7876
7905
|
"(",
|
|
7877
7906
|
"\\lparen",
|
|
7878
7907
|
")",
|
|
@@ -7928,7 +7957,7 @@ const delimiters = [
|
|
|
7928
7957
|
"\\llbracket",
|
|
7929
7958
|
"\\rrbracket",
|
|
7930
7959
|
"\u27e6",
|
|
7931
|
-
"\
|
|
7960
|
+
"\u27e7",
|
|
7932
7961
|
"\\lBrace",
|
|
7933
7962
|
"\\rBrace",
|
|
7934
7963
|
"\u2983",
|
|
@@ -7947,12 +7976,12 @@ const delimiters = [
|
|
|
7947
7976
|
"\\updownarrow",
|
|
7948
7977
|
"\\Updownarrow",
|
|
7949
7978
|
"."
|
|
7950
|
-
];
|
|
7979
|
+
]);
|
|
7951
7980
|
|
|
7952
7981
|
// Export isDelimiter for benefit of parser.
|
|
7953
|
-
const dels = ["}", "\\left", "\\middle", "\\right"];
|
|
7982
|
+
const dels = new Set(["}", "\\left", "\\middle", "\\right"]);
|
|
7954
7983
|
const isDelimiter = str => str.length > 0 &&
|
|
7955
|
-
(delimiters.
|
|
7984
|
+
(delimiters.has(str) || delimiterSizes[str] || dels.has(str));
|
|
7956
7985
|
|
|
7957
7986
|
// Metrics of the different sizes. Found by looking at TeX's output of
|
|
7958
7987
|
// $\bigl| // \Bigl| \biggl| \Biggl| \showlists$
|
|
@@ -7965,11 +7994,11 @@ function checkDelimiter(delim, context) {
|
|
|
7965
7994
|
delim = delim.body[0]; // Unwrap the braces
|
|
7966
7995
|
}
|
|
7967
7996
|
const symDelim = checkSymbolNodeType(delim);
|
|
7968
|
-
if (symDelim && delimiters.
|
|
7997
|
+
if (symDelim && delimiters.has(symDelim.text)) {
|
|
7969
7998
|
// If a character is not in the MathML operator dictionary, it will not stretch.
|
|
7970
7999
|
// Replace such characters w/characters that will stretch.
|
|
7971
|
-
if (
|
|
7972
|
-
if (
|
|
8000
|
+
if (symDelim.text === "<" || symDelim.text === "\\lt") { symDelim.text = "⟨"; }
|
|
8001
|
+
if (symDelim.text === ">" || symDelim.text === "\\gt") { symDelim.text = "⟩"; }
|
|
7973
8002
|
return symDelim;
|
|
7974
8003
|
} else if (symDelim) {
|
|
7975
8004
|
throw new ParseError(`Invalid delimiter '${symDelim.text}' after '${context.funcName}'`, delim);
|
|
@@ -7979,7 +8008,16 @@ function checkDelimiter(delim, context) {
|
|
|
7979
8008
|
}
|
|
7980
8009
|
|
|
7981
8010
|
// / \
|
|
7982
|
-
const needExplicitStretch = ["\u002F", "\u005C", "\\backslash", "\\vert", "|"];
|
|
8011
|
+
const needExplicitStretch = new Set(["\u002F", "\u005C", "\\backslash", "\u2216", "\\vert", "|"]);
|
|
8012
|
+
|
|
8013
|
+
const makeFenceMo = (delim, mode, form, isStretchy) => {
|
|
8014
|
+
const text = delim === "." ? "" : delim;
|
|
8015
|
+
const node = new MathNode("mo", [makeText(text, mode)]);
|
|
8016
|
+
node.setAttribute("fence", "true");
|
|
8017
|
+
node.setAttribute("form", form);
|
|
8018
|
+
node.setAttribute("stretchy", isStretchy ? "true" : "false");
|
|
8019
|
+
return node;
|
|
8020
|
+
};
|
|
7983
8021
|
|
|
7984
8022
|
defineFunction({
|
|
7985
8023
|
type: "delimsizing",
|
|
@@ -8030,9 +8068,9 @@ defineFunction({
|
|
|
8030
8068
|
},
|
|
8031
8069
|
mathmlBuilder: (group) => {
|
|
8032
8070
|
const children = [];
|
|
8071
|
+
const delim = group.delim === "." ? "" : group.delim;
|
|
8033
8072
|
|
|
8034
|
-
|
|
8035
|
-
children.push(makeText(group.delim, group.mode));
|
|
8073
|
+
children.push(makeText(delim, group.mode));
|
|
8036
8074
|
|
|
8037
8075
|
const node = new MathNode("mo", children);
|
|
8038
8076
|
|
|
@@ -8045,7 +8083,7 @@ defineFunction({
|
|
|
8045
8083
|
// defaults.
|
|
8046
8084
|
node.setAttribute("fence", "false");
|
|
8047
8085
|
}
|
|
8048
|
-
if (needExplicitStretch.
|
|
8086
|
+
if (needExplicitStretch.has(delim) || delim.indexOf("arrow") > -1) {
|
|
8049
8087
|
// We have to explicitly set stretchy to true.
|
|
8050
8088
|
node.setAttribute("stretchy", "true");
|
|
8051
8089
|
}
|
|
@@ -8058,7 +8096,7 @@ defineFunction({
|
|
|
8058
8096
|
|
|
8059
8097
|
function assertParsed(group) {
|
|
8060
8098
|
if (!group.body) {
|
|
8061
|
-
throw new Error("Bug: The
|
|
8099
|
+
throw new Error("Bug: The delim ParseNode wasn't fully parsed.");
|
|
8062
8100
|
}
|
|
8063
8101
|
}
|
|
8064
8102
|
|
|
@@ -8089,17 +8127,10 @@ defineFunction({
|
|
|
8089
8127
|
const delim = checkDelimiter(args[0], context);
|
|
8090
8128
|
|
|
8091
8129
|
const parser = context.parser;
|
|
8092
|
-
// Parse out the implicit body
|
|
8093
8130
|
++parser.leftrightDepth;
|
|
8094
|
-
|
|
8095
|
-
let body = parser.parseExpression(false, null, true);
|
|
8131
|
+
let body = parser.parseExpression(false, "\\right", true);
|
|
8096
8132
|
let nextToken = parser.fetch();
|
|
8097
8133
|
while (nextToken.text === "\\middle") {
|
|
8098
|
-
// `\middle`, from the ε-TeX package, ends one group and starts another group.
|
|
8099
|
-
// We had to parse this expression with `breakOnMiddle` enabled in order
|
|
8100
|
-
// to get TeX-compliant parsing of \over.
|
|
8101
|
-
// But we do not want, at this point, to end on \middle, so continue
|
|
8102
|
-
// to parse until we fetch a `\right`.
|
|
8103
8134
|
parser.consume();
|
|
8104
8135
|
const middle = parser.fetch().text;
|
|
8105
8136
|
if (!symbols.math[middle]) {
|
|
@@ -8108,11 +8139,10 @@ defineFunction({
|
|
|
8108
8139
|
checkDelimiter({ type: "atom", mode: "math", text: middle }, { funcName: "\\middle" });
|
|
8109
8140
|
body.push({ type: "middle", mode: "math", delim: middle });
|
|
8110
8141
|
parser.consume();
|
|
8111
|
-
body = body.concat(parser.parseExpression(false,
|
|
8142
|
+
body = body.concat(parser.parseExpression(false, "\\right", true));
|
|
8112
8143
|
nextToken = parser.fetch();
|
|
8113
8144
|
}
|
|
8114
8145
|
--parser.leftrightDepth;
|
|
8115
|
-
// Check the next token
|
|
8116
8146
|
parser.expect("\\right", false);
|
|
8117
8147
|
const right = assertNodeType(parser.parseFunction(), "leftright-right");
|
|
8118
8148
|
return {
|
|
@@ -8120,35 +8150,90 @@ defineFunction({
|
|
|
8120
8150
|
mode: parser.mode,
|
|
8121
8151
|
body,
|
|
8122
8152
|
left: delim.text,
|
|
8123
|
-
right: right.delim
|
|
8153
|
+
right: right.delim,
|
|
8154
|
+
isStretchy: true
|
|
8124
8155
|
};
|
|
8125
8156
|
},
|
|
8126
8157
|
mathmlBuilder: (group, style) => {
|
|
8127
8158
|
assertParsed(group);
|
|
8128
8159
|
const inner = buildExpression(group.body, style);
|
|
8129
8160
|
|
|
8130
|
-
|
|
8131
|
-
const leftNode = new MathNode("mo", [makeText(group.left, group.mode)]);
|
|
8132
|
-
leftNode.setAttribute("fence", "true");
|
|
8133
|
-
leftNode.setAttribute("form", "prefix");
|
|
8134
|
-
if (group.left === "/" || group.left === "\u005C" || group.left.indexOf("arrow") > -1) {
|
|
8135
|
-
leftNode.setAttribute("stretchy", "true");
|
|
8136
|
-
}
|
|
8161
|
+
const leftNode = makeFenceMo(group.left, group.mode, "prefix", true);
|
|
8137
8162
|
inner.unshift(leftNode);
|
|
8138
8163
|
|
|
8139
|
-
|
|
8140
|
-
|
|
8141
|
-
|
|
8142
|
-
|
|
8143
|
-
|
|
8144
|
-
|
|
8164
|
+
const rightNode = makeFenceMo(group.right, group.mode, "postfix", true);
|
|
8165
|
+
if (group.body.length > 0) {
|
|
8166
|
+
const lastElement = group.body[group.body.length - 1];
|
|
8167
|
+
if (lastElement.type === "color" && !lastElement.isTextColor) {
|
|
8168
|
+
rightNode.setAttribute("mathcolor", lastElement.color);
|
|
8169
|
+
}
|
|
8145
8170
|
}
|
|
8171
|
+
inner.push(rightNode);
|
|
8172
|
+
|
|
8173
|
+
return makeRow(inner);
|
|
8174
|
+
}
|
|
8175
|
+
});
|
|
8176
|
+
|
|
8177
|
+
defineFunction({
|
|
8178
|
+
type: "delimiter",
|
|
8179
|
+
names: Array.from(leftDelimiterNames),
|
|
8180
|
+
props: {
|
|
8181
|
+
numArgs: 0,
|
|
8182
|
+
allowedInText: true,
|
|
8183
|
+
allowedInMath: true,
|
|
8184
|
+
allowedInArgument: true
|
|
8185
|
+
},
|
|
8186
|
+
handler: ({ parser, funcName, token }) => {
|
|
8187
|
+
if (parser.mode === "text") {
|
|
8188
|
+
return {
|
|
8189
|
+
type: "textord",
|
|
8190
|
+
mode: "text",
|
|
8191
|
+
text: funcName,
|
|
8192
|
+
loc: token.loc
|
|
8193
|
+
}
|
|
8194
|
+
} else if (!parser.settings.wrapDelimiterPairs) {
|
|
8195
|
+
// Treat this token as an ordinary symbol.
|
|
8196
|
+
return {
|
|
8197
|
+
type: "atom",
|
|
8198
|
+
mode: "math",
|
|
8199
|
+
family: "open",
|
|
8200
|
+
loc: token.loc,
|
|
8201
|
+
text: funcName
|
|
8202
|
+
};
|
|
8203
|
+
}
|
|
8204
|
+
// Otherwise, try to wrap a pair of delimiters with an <mrow>.
|
|
8205
|
+
const rightDelim = leftToRight[funcName];
|
|
8206
|
+
// Parse the inner expression, looking for the corresponding right delimiter.
|
|
8207
|
+
const body = parser.parseExpression(false, rightDelim, false);
|
|
8208
|
+
const nextToken = parser.fetch().text;
|
|
8209
|
+
|
|
8210
|
+
if (nextToken !== rightDelim) {
|
|
8211
|
+
// We were unable to find a matching right delimiter.
|
|
8212
|
+
// Throw control back to renderToMathMLTree.
|
|
8213
|
+
// It will reparse the entire expression with wrapDelimiterPairs set to false.
|
|
8214
|
+
throw new ParseError("Unmatched delimiter");
|
|
8215
|
+
}
|
|
8216
|
+
parser.consume();
|
|
8217
|
+
|
|
8218
|
+
return {
|
|
8219
|
+
type: "delimiter",
|
|
8220
|
+
mode: parser.mode,
|
|
8221
|
+
body,
|
|
8222
|
+
left: funcName,
|
|
8223
|
+
right: rightDelim
|
|
8224
|
+
};
|
|
8225
|
+
},
|
|
8226
|
+
mathmlBuilder: (group, style) => {
|
|
8227
|
+
assertParsed(group);
|
|
8228
|
+
const inner = buildExpression(group.body, style);
|
|
8229
|
+
|
|
8230
|
+
const leftNode = makeFenceMo(group.left, group.mode, "prefix", false);
|
|
8231
|
+
inner.unshift(leftNode);
|
|
8232
|
+
|
|
8233
|
+
const rightNode = makeFenceMo(group.right, group.mode, "postfix", false);
|
|
8146
8234
|
if (group.body.length > 0) {
|
|
8147
8235
|
const lastElement = group.body[group.body.length - 1];
|
|
8148
8236
|
if (lastElement.type === "color" && !lastElement.isTextColor) {
|
|
8149
|
-
// \color is a switch. If the last element is of type "color" then
|
|
8150
|
-
// the user set the \color switch and left it on.
|
|
8151
|
-
// A \right delimiter turns the switch off, but the delimiter itself gets the color.
|
|
8152
8237
|
rightNode.setAttribute("mathcolor", lastElement.color);
|
|
8153
8238
|
}
|
|
8154
8239
|
}
|
|
@@ -8177,7 +8262,7 @@ defineFunction({
|
|
|
8177
8262
|
delim: delim.text
|
|
8178
8263
|
};
|
|
8179
8264
|
},
|
|
8180
|
-
mathmlBuilder: (group
|
|
8265
|
+
mathmlBuilder: (group) => {
|
|
8181
8266
|
const textNode = makeText(group.delim, group.mode);
|
|
8182
8267
|
const middleNode = new MathNode("mo", [textNode]);
|
|
8183
8268
|
middleNode.setAttribute("fence", "true");
|
|
@@ -8223,7 +8308,7 @@ const mathmlBuilder$7 = (group, style) => {
|
|
|
8223
8308
|
break
|
|
8224
8309
|
case "\\xcancel":
|
|
8225
8310
|
node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
|
|
8226
|
-
node.
|
|
8311
|
+
node.children.push(new MathNode("mrow", [], ["tml-cancel", "tml-xcancel"]));
|
|
8227
8312
|
break
|
|
8228
8313
|
// cancelto is handled in cancelto.js
|
|
8229
8314
|
case "\\longdiv":
|
|
@@ -8660,22 +8745,37 @@ defineFunction({
|
|
|
8660
8745
|
const stylArray = ["display", "text", "script", "scriptscript"];
|
|
8661
8746
|
const scriptLevel = { auto: -1, display: 0, text: 0, script: 1, scriptscript: 2 };
|
|
8662
8747
|
|
|
8748
|
+
const adjustStyle = (functionSize, originalStyle) => {
|
|
8749
|
+
// Figure out what style this fraction should be in based on the
|
|
8750
|
+
// function used
|
|
8751
|
+
let style = originalStyle;
|
|
8752
|
+
if (functionSize === "display") { //\tfrac or \cfrac
|
|
8753
|
+
// Get display style as a default.
|
|
8754
|
+
// If incoming style is sub/sup, use style.text() to get correct size.
|
|
8755
|
+
const newSize = style.level >= StyleLevel.SCRIPT ? StyleLevel.TEXT : StyleLevel.DISPLAY;
|
|
8756
|
+
style = style.withLevel(newSize);
|
|
8757
|
+
} else if (functionSize === "text" &&
|
|
8758
|
+
style.level === StyleLevel.DISPLAY) {
|
|
8759
|
+
// We're in a \tfrac but incoming style is displaystyle, so:
|
|
8760
|
+
style = style.withLevel(StyleLevel.TEXT);
|
|
8761
|
+
} else if (functionSize === "auto") {
|
|
8762
|
+
style = style.incrementLevel();
|
|
8763
|
+
} else if (functionSize === "script") {
|
|
8764
|
+
style = style.withLevel(StyleLevel.SCRIPT);
|
|
8765
|
+
} else if (functionSize === "scriptscript") {
|
|
8766
|
+
style = style.withLevel(StyleLevel.SCRIPTSCRIPT);
|
|
8767
|
+
}
|
|
8768
|
+
return style;
|
|
8769
|
+
};
|
|
8770
|
+
|
|
8663
8771
|
const mathmlBuilder$5 = (group, style) => {
|
|
8664
|
-
|
|
8665
|
-
// We may need that info for \mathchoice or for adjusting em dimensions.
|
|
8666
|
-
const childOptions = group.scriptLevel === "auto"
|
|
8667
|
-
? style.incrementLevel()
|
|
8668
|
-
: group.scriptLevel === "display"
|
|
8669
|
-
? style.withLevel(StyleLevel.TEXT)
|
|
8670
|
-
: group.scriptLevel === "text"
|
|
8671
|
-
? style.withLevel(StyleLevel.SCRIPT)
|
|
8672
|
-
: style.withLevel(StyleLevel.SCRIPTSCRIPT);
|
|
8772
|
+
style = adjustStyle(group.scriptLevel, style);
|
|
8673
8773
|
|
|
8674
8774
|
// Chromium (wrongly) continues to shrink fractions beyond scriptscriptlevel.
|
|
8675
8775
|
// So we check for levels that Chromium shrinks too small.
|
|
8676
8776
|
// If necessary, set an explicit fraction depth.
|
|
8677
|
-
const numer = buildGroup$1(group.numer,
|
|
8678
|
-
const denom = buildGroup$1(group.denom,
|
|
8777
|
+
const numer = buildGroup$1(group.numer, style);
|
|
8778
|
+
const denom = buildGroup$1(group.denom, style);
|
|
8679
8779
|
if (style.level === 3) {
|
|
8680
8780
|
numer.style.mathDepth = "2";
|
|
8681
8781
|
numer.setAttribute("scriptlevel", "2");
|
|
@@ -8728,6 +8828,7 @@ const mathmlBuilder$5 = (group, style) => {
|
|
|
8728
8828
|
defineFunction({
|
|
8729
8829
|
type: "genfrac",
|
|
8730
8830
|
names: [
|
|
8831
|
+
"\\cfrac",
|
|
8731
8832
|
"\\dfrac",
|
|
8732
8833
|
"\\frac",
|
|
8733
8834
|
"\\tfrac",
|
|
@@ -8751,6 +8852,7 @@ defineFunction({
|
|
|
8751
8852
|
let scriptLevel = "auto";
|
|
8752
8853
|
|
|
8753
8854
|
switch (funcName) {
|
|
8855
|
+
case "\\cfrac":
|
|
8754
8856
|
case "\\dfrac":
|
|
8755
8857
|
case "\\frac":
|
|
8756
8858
|
case "\\tfrac":
|
|
@@ -8777,15 +8879,10 @@ defineFunction({
|
|
|
8777
8879
|
throw new Error("Unrecognized genfrac command");
|
|
8778
8880
|
}
|
|
8779
8881
|
|
|
8780
|
-
|
|
8781
|
-
|
|
8782
|
-
|
|
8783
|
-
|
|
8784
|
-
break;
|
|
8785
|
-
case "\\tfrac":
|
|
8786
|
-
case "\\tbinom":
|
|
8787
|
-
scriptLevel = "text";
|
|
8788
|
-
break;
|
|
8882
|
+
if (funcName === "\\cfrac" || funcName.startsWith("\\d")) {
|
|
8883
|
+
scriptLevel = "display";
|
|
8884
|
+
} else if (funcName.startsWith("\\t")) {
|
|
8885
|
+
scriptLevel = "text";
|
|
8789
8886
|
}
|
|
8790
8887
|
|
|
8791
8888
|
return {
|
|
@@ -8804,31 +8901,6 @@ defineFunction({
|
|
|
8804
8901
|
mathmlBuilder: mathmlBuilder$5
|
|
8805
8902
|
});
|
|
8806
8903
|
|
|
8807
|
-
defineFunction({
|
|
8808
|
-
type: "genfrac",
|
|
8809
|
-
names: ["\\cfrac"],
|
|
8810
|
-
props: {
|
|
8811
|
-
numArgs: 2
|
|
8812
|
-
},
|
|
8813
|
-
handler: ({ parser, funcName }, args) => {
|
|
8814
|
-
const numer = args[0];
|
|
8815
|
-
const denom = args[1];
|
|
8816
|
-
|
|
8817
|
-
return {
|
|
8818
|
-
type: "genfrac",
|
|
8819
|
-
mode: parser.mode,
|
|
8820
|
-
continued: true,
|
|
8821
|
-
numer,
|
|
8822
|
-
denom,
|
|
8823
|
-
hasBarLine: true,
|
|
8824
|
-
leftDelim: null,
|
|
8825
|
-
rightDelim: null,
|
|
8826
|
-
scriptLevel: "display",
|
|
8827
|
-
barSize: null
|
|
8828
|
-
};
|
|
8829
|
-
}
|
|
8830
|
-
});
|
|
8831
|
-
|
|
8832
8904
|
// Infix generalized fractions -- these are not rendered directly, but replaced
|
|
8833
8905
|
// immediately by one of the variants above.
|
|
8834
8906
|
defineFunction({
|
|
@@ -9657,8 +9729,16 @@ const binrelClass = (arg) => {
|
|
|
9657
9729
|
const atom = arg.type === "ordgroup" && arg.body.length && arg.body.length === 1
|
|
9658
9730
|
? arg.body[0]
|
|
9659
9731
|
: arg;
|
|
9660
|
-
if (atom.type === "atom"
|
|
9661
|
-
|
|
9732
|
+
if (atom.type === "atom") {
|
|
9733
|
+
// BIN args are sometimes changed to OPEN, so check the original family.
|
|
9734
|
+
const family = arg.body.length > 0 && arg.body[0].text && symbols.math[arg.body[0].text]
|
|
9735
|
+
? symbols.math[arg.body[0].text].group
|
|
9736
|
+
: atom.family;
|
|
9737
|
+
if (family === "bin" || family === "rel") {
|
|
9738
|
+
return "m" + family;
|
|
9739
|
+
} else {
|
|
9740
|
+
return "mord";
|
|
9741
|
+
}
|
|
9662
9742
|
} else {
|
|
9663
9743
|
return "mord";
|
|
9664
9744
|
}
|
|
@@ -10229,6 +10309,14 @@ const mathmlBuilder$1 = (group, style) => {
|
|
|
10229
10309
|
if ((node.type === "mrow" || node.type === "mpadded") && node.children.length === 1 &&
|
|
10230
10310
|
node.children[0] instanceof MathNode) {
|
|
10231
10311
|
node = node.children[0];
|
|
10312
|
+
} else if (node.type === "mrow" && node.children.length === 2 &&
|
|
10313
|
+
node.children[0] instanceof MathNode &&
|
|
10314
|
+
node.children[1] instanceof MathNode &&
|
|
10315
|
+
node.children[1].type === "mspace" && !node.children[1].attributes.width &&
|
|
10316
|
+
node.children[1].children.length === 0) {
|
|
10317
|
+
// This is a workaround for a Firefox bug that applies spacing to
|
|
10318
|
+
// an <mi> with mathvariant="normal".
|
|
10319
|
+
node = node.children[0];
|
|
10232
10320
|
}
|
|
10233
10321
|
switch (node.type) {
|
|
10234
10322
|
case "mi":
|
|
@@ -11499,8 +11587,8 @@ defineFunctionBuilders({
|
|
|
11499
11587
|
node.setAttribute("mathvariant", "normal");
|
|
11500
11588
|
if (text.text.length === 1) {
|
|
11501
11589
|
// A Firefox bug will apply spacing here, but there should be none. Fix it.
|
|
11502
|
-
|
|
11503
|
-
node
|
|
11590
|
+
const mspace = new MathNode("mspace", []);
|
|
11591
|
+
node = new MathNode("mrow", [node, mspace]);
|
|
11504
11592
|
}
|
|
11505
11593
|
}
|
|
11506
11594
|
return node
|
|
@@ -13037,7 +13125,7 @@ class Parser {
|
|
|
13037
13125
|
* Parses an "expression", which is a list of atoms.
|
|
13038
13126
|
*
|
|
13039
13127
|
* `breakOnInfix`: Should the parsing stop when we hit infix nodes? This
|
|
13040
|
-
* happens when functions have higher precedence
|
|
13128
|
+
* happens when functions have higher precedence than infix
|
|
13041
13129
|
* nodes in implicit parses.
|
|
13042
13130
|
*
|
|
13043
13131
|
* `breakOnTokenText`: The text of the token that the expression should end
|
|
@@ -13645,7 +13733,7 @@ class Parser {
|
|
|
13645
13733
|
) {
|
|
13646
13734
|
const firstToken = this.fetch();
|
|
13647
13735
|
const text = firstToken.text;
|
|
13648
|
-
|
|
13736
|
+
if (name === "argument to '\\left'") { return this.parseSymbol() }
|
|
13649
13737
|
let result;
|
|
13650
13738
|
// Try to parse an open brace or \begingroup
|
|
13651
13739
|
if (text === "{" || text === "\\begingroup" || text === "\\toggle") {
|
|
@@ -13678,6 +13766,12 @@ class Parser {
|
|
|
13678
13766
|
result = this.parseFunction(breakOnTokenText, name) || this.parseSymbol();
|
|
13679
13767
|
if (result == null && text[0] === "\\" &&
|
|
13680
13768
|
!Object.prototype.hasOwnProperty.call(implicitCommands, text )) {
|
|
13769
|
+
if (this.settings.throwOnError) {
|
|
13770
|
+
throw new ParseError("Unsupported function name: " + text, firstToken);
|
|
13771
|
+
}
|
|
13772
|
+
// For people getting dyanamically rendered math, it's better to
|
|
13773
|
+
// show the unsupported command in red rather than panicking for every
|
|
13774
|
+
// partially written expression.
|
|
13681
13775
|
result = this.formatUnsupportedCmd(text);
|
|
13682
13776
|
this.consume();
|
|
13683
13777
|
}
|
|
@@ -13786,7 +13880,8 @@ class Parser {
|
|
|
13786
13880
|
let symbol;
|
|
13787
13881
|
if (symbols[this.mode][text]) {
|
|
13788
13882
|
let group = symbols[this.mode][text].group;
|
|
13789
|
-
if (group === "bin" &&
|
|
13883
|
+
if (group === "bin" &&
|
|
13884
|
+
(binLeftCancellers.includes(this.prevAtomType) || this.prevAtomType === "")) {
|
|
13790
13885
|
// Change from a binary operator to a unary (prefix) operator
|
|
13791
13886
|
group = "open";
|
|
13792
13887
|
}
|
|
@@ -13882,11 +13977,27 @@ const parseTree = function(toParse, settings) {
|
|
|
13882
13977
|
if (!(typeof toParse === "string" || toParse instanceof String)) {
|
|
13883
13978
|
throw new TypeError("Temml can only parse string typed expression")
|
|
13884
13979
|
}
|
|
13885
|
-
|
|
13886
|
-
|
|
13887
|
-
|
|
13980
|
+
let tree;
|
|
13981
|
+
let parser;
|
|
13982
|
+
try {
|
|
13983
|
+
parser = new Parser(toParse, settings);
|
|
13984
|
+
// Blank out any \df@tag to avoid spurious "Duplicate \tag" errors
|
|
13985
|
+
delete parser.gullet.macros.current["\\df@tag"];
|
|
13888
13986
|
|
|
13889
|
-
|
|
13987
|
+
tree = parser.parse();
|
|
13988
|
+
} catch (error) {
|
|
13989
|
+
if (error.toString() === "ParseError: Unmatched delimiter") {
|
|
13990
|
+
// Abandon the attempt to wrap delimiter pairs in an <mrow>.
|
|
13991
|
+
// Try again, and put each delimiter into an <mo> element.
|
|
13992
|
+
settings.wrapDelimiterPairs = false;
|
|
13993
|
+
parser = new Parser(toParse, settings);
|
|
13994
|
+
// Blank out any \df@tag to avoid spurious "Duplicate \tag" errors
|
|
13995
|
+
delete parser.gullet.macros.current["\\df@tag"];
|
|
13996
|
+
tree = parser.parse();
|
|
13997
|
+
} else {
|
|
13998
|
+
throw error;
|
|
13999
|
+
}
|
|
14000
|
+
}
|
|
13890
14001
|
|
|
13891
14002
|
// LaTeX ignores a \tag placed outside an AMS environment.
|
|
13892
14003
|
if (!(tree.length > 0 && tree[0].type && tree[0].type === "array" && tree[0].addEqnNum)) {
|
|
@@ -14063,7 +14174,7 @@ class Style {
|
|
|
14063
14174
|
* https://mit-license.org/
|
|
14064
14175
|
*/
|
|
14065
14176
|
|
|
14066
|
-
const version = "0.
|
|
14177
|
+
const version = "0.13.02";
|
|
14067
14178
|
|
|
14068
14179
|
function postProcess(block) {
|
|
14069
14180
|
const labelMap = {};
|