katex 0.15.0 → 0.15.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/README.md +3 -3
- package/contrib/copy-tex/README.md +3 -3
- package/contrib/mathtex-script-type/README.md +5 -5
- package/contrib/mhchem/README.md +1 -1
- package/dist/README.md +3 -3
- package/dist/katex.css +1 -1
- package/dist/katex.js +212 -131
- package/dist/katex.min.css +1 -1
- package/dist/katex.min.js +1 -1
- package/dist/katex.mjs +115 -39
- package/package.json +1 -1
- package/src/Namespace.js +9 -4
- package/src/Parser.js +21 -0
- package/src/environments/array.js +72 -18
- package/src/parseNode.js +2 -1
- package/src/parseTree.js +2 -2
package/dist/katex.mjs
CHANGED
|
@@ -9983,6 +9983,17 @@ function defineEnvironment(_ref) {
|
|
|
9983
9983
|
}
|
|
9984
9984
|
}
|
|
9985
9985
|
|
|
9986
|
+
/**
|
|
9987
|
+
* All registered global/built-in macros.
|
|
9988
|
+
* `macros.js` exports this same dictionary again and makes it public.
|
|
9989
|
+
* `Parser.js` requires this dictionary via `macros.js`.
|
|
9990
|
+
*/
|
|
9991
|
+
var _macros = {}; // This function might one day accept an additional argument and do more things.
|
|
9992
|
+
|
|
9993
|
+
function defineMacro(name, body) {
|
|
9994
|
+
_macros[name] = body;
|
|
9995
|
+
}
|
|
9996
|
+
|
|
9986
9997
|
// Helper functions
|
|
9987
9998
|
function getHLines(parser) {
|
|
9988
9999
|
// Return an array. The array length = number of hlines.
|
|
@@ -10007,7 +10018,19 @@ var validateAmsEnvironmentContext = context => {
|
|
|
10007
10018
|
if (!settings.displayMode) {
|
|
10008
10019
|
throw new ParseError("{" + context.envName + "} can be used only in" + " display mode.");
|
|
10009
10020
|
}
|
|
10010
|
-
};
|
|
10021
|
+
}; // autoTag (an argument to parseArray) can be one of three values:
|
|
10022
|
+
// * undefined: Regular (not-top-level) array; no tags on each row
|
|
10023
|
+
// * true: Automatic equation numbering, overridable by \tag
|
|
10024
|
+
// * false: Tags allowed on each row, but no automatic numbering
|
|
10025
|
+
// This function *doesn't* work with the "split" environment name.
|
|
10026
|
+
|
|
10027
|
+
|
|
10028
|
+
function getAutoTag(name) {
|
|
10029
|
+
if (name.indexOf("ed") === -1) {
|
|
10030
|
+
return name.indexOf("*") === -1;
|
|
10031
|
+
} // return undefined;
|
|
10032
|
+
|
|
10033
|
+
}
|
|
10011
10034
|
/**
|
|
10012
10035
|
* Parse the body of the environment, with rows delimited by \\ and
|
|
10013
10036
|
* columns delimited by &, and create a nested list in row-major order
|
|
@@ -10023,7 +10046,7 @@ function parseArray(parser, _ref, style) {
|
|
|
10023
10046
|
cols,
|
|
10024
10047
|
arraystretch,
|
|
10025
10048
|
colSeparationType,
|
|
10026
|
-
|
|
10049
|
+
autoTag,
|
|
10027
10050
|
singleRow,
|
|
10028
10051
|
emptySingleRow,
|
|
10029
10052
|
maxNumCols,
|
|
@@ -10058,7 +10081,29 @@ function parseArray(parser, _ref, style) {
|
|
|
10058
10081
|
var row = [];
|
|
10059
10082
|
var body = [row];
|
|
10060
10083
|
var rowGaps = [];
|
|
10061
|
-
var hLinesBeforeRow = [];
|
|
10084
|
+
var hLinesBeforeRow = [];
|
|
10085
|
+
var tags = autoTag != null ? [] : undefined; // amsmath uses \global\@eqnswtrue and \global\@eqnswfalse to represent
|
|
10086
|
+
// whether this row should have an equation number. Simulate this with
|
|
10087
|
+
// a \@eqnsw macro set to 1 or 0.
|
|
10088
|
+
|
|
10089
|
+
function beginRow() {
|
|
10090
|
+
if (autoTag) {
|
|
10091
|
+
parser.gullet.macros.set("\\@eqnsw", "1", true);
|
|
10092
|
+
}
|
|
10093
|
+
}
|
|
10094
|
+
|
|
10095
|
+
function endRow() {
|
|
10096
|
+
if (tags) {
|
|
10097
|
+
if (parser.gullet.macros.get("\\df@tag")) {
|
|
10098
|
+
tags.push(parser.subparse([new Token("\\df@tag")]));
|
|
10099
|
+
parser.gullet.macros.set("\\df@tag", undefined, true);
|
|
10100
|
+
} else {
|
|
10101
|
+
tags.push(Boolean(autoTag) && parser.gullet.macros.get("\\@eqnsw") === "1");
|
|
10102
|
+
}
|
|
10103
|
+
}
|
|
10104
|
+
}
|
|
10105
|
+
|
|
10106
|
+
beginRow(); // Test for \hline at the top of the array.
|
|
10062
10107
|
|
|
10063
10108
|
hLinesBeforeRow.push(getHLines(parser));
|
|
10064
10109
|
|
|
@@ -10099,10 +10144,11 @@ function parseArray(parser, _ref, style) {
|
|
|
10099
10144
|
|
|
10100
10145
|
parser.consume();
|
|
10101
10146
|
} else if (next === "\\end") {
|
|
10102
|
-
// Arrays terminate newlines with `\crcr` which consumes a `\cr` if
|
|
10147
|
+
endRow(); // Arrays terminate newlines with `\crcr` which consumes a `\cr` if
|
|
10103
10148
|
// the last line is empty. However, AMS environments keep the
|
|
10104
10149
|
// empty row if it's the only one.
|
|
10105
10150
|
// NOTE: Currently, `cell` is the last item added into `row`.
|
|
10151
|
+
|
|
10106
10152
|
if (row.length === 1 && cell.type === "styling" && cell.body[0].body.length === 0 && (body.length > 1 || !emptySingleRow)) {
|
|
10107
10153
|
body.pop();
|
|
10108
10154
|
}
|
|
@@ -10124,11 +10170,13 @@ function parseArray(parser, _ref, style) {
|
|
|
10124
10170
|
size = parser.parseSizeGroup(true);
|
|
10125
10171
|
}
|
|
10126
10172
|
|
|
10127
|
-
rowGaps.push(size ? size.value : null);
|
|
10173
|
+
rowGaps.push(size ? size.value : null);
|
|
10174
|
+
endRow(); // check for \hline(s) following the row separator
|
|
10128
10175
|
|
|
10129
10176
|
hLinesBeforeRow.push(getHLines(parser));
|
|
10130
10177
|
row = [];
|
|
10131
10178
|
body.push(row);
|
|
10179
|
+
beginRow();
|
|
10132
10180
|
} else {
|
|
10133
10181
|
throw new ParseError("Expected & or \\\\ or \\cr or \\end", parser.nextToken);
|
|
10134
10182
|
}
|
|
@@ -10149,7 +10197,7 @@ function parseArray(parser, _ref, style) {
|
|
|
10149
10197
|
hskipBeforeAndAfter,
|
|
10150
10198
|
hLinesBeforeRow,
|
|
10151
10199
|
colSeparationType,
|
|
10152
|
-
|
|
10200
|
+
tags,
|
|
10153
10201
|
leqno
|
|
10154
10202
|
};
|
|
10155
10203
|
} // Decides on a style for cells in an array according to whether the given
|
|
@@ -10287,20 +10335,33 @@ var htmlBuilder$7 = function htmlBuilder(group, options) {
|
|
|
10287
10335
|
var cols = [];
|
|
10288
10336
|
var colSep;
|
|
10289
10337
|
var colDescrNum;
|
|
10290
|
-
var
|
|
10338
|
+
var tagSpans = [];
|
|
10291
10339
|
|
|
10292
|
-
if (group.
|
|
10293
|
-
// An environment with automatic equation numbers.
|
|
10294
|
-
// Create node(s)
|
|
10340
|
+
if (group.tags && group.tags.some(tag => tag)) {
|
|
10341
|
+
// An environment with manual tags and/or automatic equation numbers.
|
|
10342
|
+
// Create node(s), the latter of which trigger CSS counter increment.
|
|
10295
10343
|
for (r = 0; r < nr; ++r) {
|
|
10296
10344
|
var rw = body[r];
|
|
10297
10345
|
var shift = rw.pos - offset;
|
|
10298
|
-
var
|
|
10299
|
-
|
|
10300
|
-
|
|
10301
|
-
|
|
10346
|
+
var tag = group.tags[r];
|
|
10347
|
+
var tagSpan = void 0;
|
|
10348
|
+
|
|
10349
|
+
if (tag === true) {
|
|
10350
|
+
// automatic numbering
|
|
10351
|
+
tagSpan = buildCommon.makeSpan(["eqn-num"], [], options);
|
|
10352
|
+
} else if (tag === false) {
|
|
10353
|
+
// \nonumber/\notag or starred environment
|
|
10354
|
+
tagSpan = buildCommon.makeSpan([], [], options);
|
|
10355
|
+
} else {
|
|
10356
|
+
// manual \tag
|
|
10357
|
+
tagSpan = buildCommon.makeSpan([], buildExpression$1(tag, options, true), options);
|
|
10358
|
+
}
|
|
10359
|
+
|
|
10360
|
+
tagSpan.depth = rw.depth;
|
|
10361
|
+
tagSpan.height = rw.height;
|
|
10362
|
+
tagSpans.push({
|
|
10302
10363
|
type: "elem",
|
|
10303
|
-
elem:
|
|
10364
|
+
elem: tagSpan,
|
|
10304
10365
|
shift
|
|
10305
10366
|
});
|
|
10306
10367
|
}
|
|
@@ -10436,12 +10497,12 @@ var htmlBuilder$7 = function htmlBuilder(group, options) {
|
|
|
10436
10497
|
}, options);
|
|
10437
10498
|
}
|
|
10438
10499
|
|
|
10439
|
-
if (
|
|
10500
|
+
if (tagSpans.length === 0) {
|
|
10440
10501
|
return buildCommon.makeSpan(["mord"], [body], options);
|
|
10441
10502
|
} else {
|
|
10442
10503
|
var eqnNumCol = buildCommon.makeVList({
|
|
10443
10504
|
positionType: "individualShift",
|
|
10444
|
-
children:
|
|
10505
|
+
children: tagSpans
|
|
10445
10506
|
}, options);
|
|
10446
10507
|
eqnNumCol = buildCommon.makeSpan(["tag"], [eqnNumCol], options);
|
|
10447
10508
|
return buildCommon.makeFragment([body, eqnNumCol]);
|
|
@@ -10467,7 +10528,7 @@ var mathmlBuilder$6 = function mathmlBuilder(group, options) {
|
|
|
10467
10528
|
row.push(new mathMLTree.MathNode("mtd", [buildGroup(rw[j], options)]));
|
|
10468
10529
|
}
|
|
10469
10530
|
|
|
10470
|
-
if (group.
|
|
10531
|
+
if (group.tags && group.tags[i]) {
|
|
10471
10532
|
row.unshift(glue);
|
|
10472
10533
|
row.push(glue);
|
|
10473
10534
|
|
|
@@ -10602,13 +10663,14 @@ var alignedHandler = function alignedHandler(context, args) {
|
|
|
10602
10663
|
|
|
10603
10664
|
var cols = [];
|
|
10604
10665
|
var separationType = context.envName.indexOf("at") > -1 ? "alignat" : "align";
|
|
10666
|
+
var isSplit = context.envName === "split";
|
|
10605
10667
|
var res = parseArray(context.parser, {
|
|
10606
10668
|
cols,
|
|
10607
10669
|
addJot: true,
|
|
10608
|
-
|
|
10670
|
+
autoTag: isSplit ? undefined : getAutoTag(context.envName),
|
|
10609
10671
|
emptySingleRow: true,
|
|
10610
10672
|
colSeparationType: separationType,
|
|
10611
|
-
maxNumCols:
|
|
10673
|
+
maxNumCols: isSplit ? 2 : undefined,
|
|
10612
10674
|
leqno: context.parser.settings.leqno
|
|
10613
10675
|
}, "display"); // Determining number of columns.
|
|
10614
10676
|
// 1. If the first argument is given, we use it as a number of columns,
|
|
@@ -10968,7 +11030,7 @@ defineEnvironment({
|
|
|
10968
11030
|
}],
|
|
10969
11031
|
addJot: true,
|
|
10970
11032
|
colSeparationType: "gather",
|
|
10971
|
-
|
|
11033
|
+
autoTag: getAutoTag(context.envName),
|
|
10972
11034
|
emptySingleRow: true,
|
|
10973
11035
|
leqno: context.parser.settings.leqno
|
|
10974
11036
|
};
|
|
@@ -11001,7 +11063,7 @@ defineEnvironment({
|
|
|
11001
11063
|
handler(context) {
|
|
11002
11064
|
validateAmsEnvironmentContext(context);
|
|
11003
11065
|
var res = {
|
|
11004
|
-
|
|
11066
|
+
autoTag: getAutoTag(context.envName),
|
|
11005
11067
|
emptySingleRow: true,
|
|
11006
11068
|
singleRow: true,
|
|
11007
11069
|
maxNumCols: 1,
|
|
@@ -11027,7 +11089,9 @@ defineEnvironment({
|
|
|
11027
11089
|
|
|
11028
11090
|
htmlBuilder: htmlBuilder$7,
|
|
11029
11091
|
mathmlBuilder: mathmlBuilder$6
|
|
11030
|
-
});
|
|
11092
|
+
});
|
|
11093
|
+
defineMacro("\\nonumber", "\\gdef\\@eqnsw{0}");
|
|
11094
|
+
defineMacro("\\notag", "\\nonumber"); // Catch \hline outside array environment
|
|
11031
11095
|
|
|
11032
11096
|
defineFunction({
|
|
11033
11097
|
type: "text",
|
|
@@ -13153,17 +13217,6 @@ defineFunction({
|
|
|
13153
13217
|
mathmlBuilder: mathmlBuilder$1
|
|
13154
13218
|
});
|
|
13155
13219
|
|
|
13156
|
-
/**
|
|
13157
|
-
* All registered global/built-in macros.
|
|
13158
|
-
* `macros.js` exports this same dictionary again and makes it public.
|
|
13159
|
-
* `Parser.js` requires this dictionary via `macros.js`.
|
|
13160
|
-
*/
|
|
13161
|
-
var _macros = {}; // This function might one day accept an additional argument and do more things.
|
|
13162
|
-
|
|
13163
|
-
function defineMacro(name, body) {
|
|
13164
|
-
_macros[name] = body;
|
|
13165
|
-
}
|
|
13166
|
-
|
|
13167
13220
|
// NOTE: Unlike most `htmlBuilder`s, this one handles not only
|
|
13168
13221
|
// "operatorname", but also "supsub" since \operatorname* can
|
|
13169
13222
|
// affect super/subscripting.
|
|
@@ -14812,7 +14865,7 @@ class Namespace {
|
|
|
14812
14865
|
|
|
14813
14866
|
for (var undef in undefs) {
|
|
14814
14867
|
if (undefs.hasOwnProperty(undef)) {
|
|
14815
|
-
if (undefs[undef]
|
|
14868
|
+
if (undefs[undef] == null) {
|
|
14816
14869
|
delete this.current[undef];
|
|
14817
14870
|
} else {
|
|
14818
14871
|
this.current[undef] = undefs[undef];
|
|
@@ -14862,6 +14915,7 @@ class Namespace {
|
|
|
14862
14915
|
* Local set() sets the current value and (when appropriate) adds an undo
|
|
14863
14916
|
* operation to the undo stack. Global set() may change the undo
|
|
14864
14917
|
* operation at every level, so takes time linear in their number.
|
|
14918
|
+
* A value of undefined means to delete existing definitions.
|
|
14865
14919
|
*/
|
|
14866
14920
|
|
|
14867
14921
|
|
|
@@ -14893,7 +14947,11 @@ class Namespace {
|
|
|
14893
14947
|
}
|
|
14894
14948
|
}
|
|
14895
14949
|
|
|
14896
|
-
|
|
14950
|
+
if (value == null) {
|
|
14951
|
+
delete this.current[name];
|
|
14952
|
+
} else {
|
|
14953
|
+
this.current[name] = value;
|
|
14954
|
+
}
|
|
14897
14955
|
}
|
|
14898
14956
|
|
|
14899
14957
|
}
|
|
@@ -16831,6 +16889,25 @@ class Parser {
|
|
|
16831
16889
|
this.gullet.endGroups();
|
|
16832
16890
|
}
|
|
16833
16891
|
}
|
|
16892
|
+
/**
|
|
16893
|
+
* Fully parse a separate sequence of tokens as a separate job.
|
|
16894
|
+
* Tokens should be specified in reverse order, as in a MacroDefinition.
|
|
16895
|
+
*/
|
|
16896
|
+
|
|
16897
|
+
|
|
16898
|
+
subparse(tokens) {
|
|
16899
|
+
// Save the next token from the current job.
|
|
16900
|
+
var oldToken = this.nextToken;
|
|
16901
|
+
this.consume(); // Run the new job, terminating it with an excess '}'
|
|
16902
|
+
|
|
16903
|
+
this.gullet.pushToken(new Token("}"));
|
|
16904
|
+
this.gullet.pushTokens(tokens);
|
|
16905
|
+
var parse = this.parseExpression(false);
|
|
16906
|
+
this.expect("}"); // Restore the next token from the current job.
|
|
16907
|
+
|
|
16908
|
+
this.nextToken = oldToken;
|
|
16909
|
+
return parse;
|
|
16910
|
+
}
|
|
16834
16911
|
|
|
16835
16912
|
/**
|
|
16836
16913
|
* Parses an "expression", which is a list of atoms.
|
|
@@ -17772,12 +17849,11 @@ var parseTree = function parseTree(toParse, settings) {
|
|
|
17772
17849
|
throw new ParseError("\\tag works only in display equations");
|
|
17773
17850
|
}
|
|
17774
17851
|
|
|
17775
|
-
parser.gullet.feed("\\df@tag");
|
|
17776
17852
|
tree = [{
|
|
17777
17853
|
type: "tag",
|
|
17778
17854
|
mode: "text",
|
|
17779
17855
|
body: tree,
|
|
17780
|
-
tag: parser.
|
|
17856
|
+
tag: parser.subparse([new Token("\\df@tag")])
|
|
17781
17857
|
}];
|
|
17782
17858
|
}
|
|
17783
17859
|
|
|
@@ -17879,7 +17955,7 @@ var katex = {
|
|
|
17879
17955
|
/**
|
|
17880
17956
|
* Current KaTeX version
|
|
17881
17957
|
*/
|
|
17882
|
-
version: "0.15.
|
|
17958
|
+
version: "0.15.1",
|
|
17883
17959
|
|
|
17884
17960
|
/**
|
|
17885
17961
|
* Renders the given LaTeX into an HTML+MathML combination, and adds
|
package/package.json
CHANGED
package/src/Namespace.js
CHANGED
|
@@ -15,7 +15,7 @@ export type Mapping<Value> = {[string]: Value};
|
|
|
15
15
|
export default class Namespace<Value> {
|
|
16
16
|
current: Mapping<Value>;
|
|
17
17
|
builtins: Mapping<Value>;
|
|
18
|
-
undefStack: Mapping
|
|
18
|
+
undefStack: Mapping<?Value>[];
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Both arguments are optional. The first argument is an object of
|
|
@@ -48,7 +48,7 @@ export default class Namespace<Value> {
|
|
|
48
48
|
const undefs = this.undefStack.pop();
|
|
49
49
|
for (const undef in undefs) {
|
|
50
50
|
if (undefs.hasOwnProperty(undef)) {
|
|
51
|
-
if (undefs[undef]
|
|
51
|
+
if (undefs[undef] == null) {
|
|
52
52
|
delete this.current[undef];
|
|
53
53
|
} else {
|
|
54
54
|
this.current[undef] = undefs[undef];
|
|
@@ -97,8 +97,9 @@ export default class Namespace<Value> {
|
|
|
97
97
|
* Local set() sets the current value and (when appropriate) adds an undo
|
|
98
98
|
* operation to the undo stack. Global set() may change the undo
|
|
99
99
|
* operation at every level, so takes time linear in their number.
|
|
100
|
+
* A value of undefined means to delete existing definitions.
|
|
100
101
|
*/
|
|
101
|
-
set(name: string, value: Value, global: boolean = false) {
|
|
102
|
+
set(name: string, value: ?Value, global: boolean = false) {
|
|
102
103
|
if (global) {
|
|
103
104
|
// Global set is equivalent to setting in all groups. Simulate this
|
|
104
105
|
// by destroying any undos currently scheduled for this name,
|
|
@@ -119,6 +120,10 @@ export default class Namespace<Value> {
|
|
|
119
120
|
top[name] = this.current[name];
|
|
120
121
|
}
|
|
121
122
|
}
|
|
122
|
-
|
|
123
|
+
if (value == null) {
|
|
124
|
+
delete this.current[name];
|
|
125
|
+
} else {
|
|
126
|
+
this.current[name] = value;
|
|
127
|
+
}
|
|
123
128
|
}
|
|
124
129
|
}
|
package/src/Parser.js
CHANGED
|
@@ -150,6 +150,27 @@ export default class Parser {
|
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
152
|
|
|
153
|
+
/**
|
|
154
|
+
* Fully parse a separate sequence of tokens as a separate job.
|
|
155
|
+
* Tokens should be specified in reverse order, as in a MacroDefinition.
|
|
156
|
+
*/
|
|
157
|
+
subparse(tokens: Token[]): AnyParseNode[] {
|
|
158
|
+
// Save the next token from the current job.
|
|
159
|
+
const oldToken = this.nextToken;
|
|
160
|
+
this.consume();
|
|
161
|
+
|
|
162
|
+
// Run the new job, terminating it with an excess '}'
|
|
163
|
+
this.gullet.pushToken(new Token("}"));
|
|
164
|
+
this.gullet.pushTokens(tokens);
|
|
165
|
+
const parse = this.parseExpression(false);
|
|
166
|
+
this.expect("}");
|
|
167
|
+
|
|
168
|
+
// Restore the next token from the current job.
|
|
169
|
+
this.nextToken = oldToken;
|
|
170
|
+
|
|
171
|
+
return parse;
|
|
172
|
+
}
|
|
173
|
+
|
|
153
174
|
static endOfExpression: string[] = ["}", "\\endgroup", "\\end", "\\right", "&"];
|
|
154
175
|
|
|
155
176
|
/**
|
|
@@ -4,10 +4,12 @@ import Style from "../Style";
|
|
|
4
4
|
import defineEnvironment from "../defineEnvironment";
|
|
5
5
|
import {parseCD} from "./cd";
|
|
6
6
|
import defineFunction from "../defineFunction";
|
|
7
|
+
import defineMacro from "../defineMacro";
|
|
7
8
|
import mathMLTree from "../mathMLTree";
|
|
8
9
|
import ParseError from "../ParseError";
|
|
9
10
|
import {assertNodeType, assertSymbolNodeType} from "../parseNode";
|
|
10
11
|
import {checkSymbolNodeType} from "../parseNode";
|
|
12
|
+
import {Token} from "../Token";
|
|
11
13
|
import {calculateSize, makeEm} from "../units";
|
|
12
14
|
import utils from "../utils";
|
|
13
15
|
|
|
@@ -54,6 +56,18 @@ const validateAmsEnvironmentContext = context => {
|
|
|
54
56
|
}
|
|
55
57
|
};
|
|
56
58
|
|
|
59
|
+
// autoTag (an argument to parseArray) can be one of three values:
|
|
60
|
+
// * undefined: Regular (not-top-level) array; no tags on each row
|
|
61
|
+
// * true: Automatic equation numbering, overridable by \tag
|
|
62
|
+
// * false: Tags allowed on each row, but no automatic numbering
|
|
63
|
+
// This function *doesn't* work with the "split" environment name.
|
|
64
|
+
function getAutoTag(name): ?boolean {
|
|
65
|
+
if (name.indexOf("ed") === -1) {
|
|
66
|
+
return name.indexOf("*") === -1;
|
|
67
|
+
}
|
|
68
|
+
// return undefined;
|
|
69
|
+
}
|
|
70
|
+
|
|
57
71
|
/**
|
|
58
72
|
* Parse the body of the environment, with rows delimited by \\ and
|
|
59
73
|
* columns delimited by &, and create a nested list in row-major order
|
|
@@ -68,7 +82,7 @@ function parseArray(
|
|
|
68
82
|
cols,
|
|
69
83
|
arraystretch,
|
|
70
84
|
colSeparationType,
|
|
71
|
-
|
|
85
|
+
autoTag,
|
|
72
86
|
singleRow,
|
|
73
87
|
emptySingleRow,
|
|
74
88
|
maxNumCols,
|
|
@@ -79,7 +93,7 @@ function parseArray(
|
|
|
79
93
|
cols?: AlignSpec[],
|
|
80
94
|
arraystretch?: number,
|
|
81
95
|
colSeparationType?: ColSeparationType,
|
|
82
|
-
|
|
96
|
+
autoTag?: ?boolean,
|
|
83
97
|
singleRow?: boolean,
|
|
84
98
|
emptySingleRow?: boolean,
|
|
85
99
|
maxNumCols?: number,
|
|
@@ -116,6 +130,29 @@ function parseArray(
|
|
|
116
130
|
const rowGaps = [];
|
|
117
131
|
const hLinesBeforeRow = [];
|
|
118
132
|
|
|
133
|
+
const tags = (autoTag != null ? [] : undefined);
|
|
134
|
+
|
|
135
|
+
// amsmath uses \global\@eqnswtrue and \global\@eqnswfalse to represent
|
|
136
|
+
// whether this row should have an equation number. Simulate this with
|
|
137
|
+
// a \@eqnsw macro set to 1 or 0.
|
|
138
|
+
function beginRow() {
|
|
139
|
+
if (autoTag) {
|
|
140
|
+
parser.gullet.macros.set("\\@eqnsw", "1", true);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function endRow() {
|
|
144
|
+
if (tags) {
|
|
145
|
+
if (parser.gullet.macros.get("\\df@tag")) {
|
|
146
|
+
tags.push(parser.subparse([new Token("\\df@tag")]));
|
|
147
|
+
parser.gullet.macros.set("\\df@tag", undefined, true);
|
|
148
|
+
} else {
|
|
149
|
+
tags.push(Boolean(autoTag) &&
|
|
150
|
+
parser.gullet.macros.get("\\@eqnsw") === "1");
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
beginRow();
|
|
155
|
+
|
|
119
156
|
// Test for \hline at the top of the array.
|
|
120
157
|
hLinesBeforeRow.push(getHLines(parser));
|
|
121
158
|
|
|
@@ -154,6 +191,7 @@ function parseArray(
|
|
|
154
191
|
}
|
|
155
192
|
parser.consume();
|
|
156
193
|
} else if (next === "\\end") {
|
|
194
|
+
endRow();
|
|
157
195
|
// Arrays terminate newlines with `\crcr` which consumes a `\cr` if
|
|
158
196
|
// the last line is empty. However, AMS environments keep the
|
|
159
197
|
// empty row if it's the only one.
|
|
@@ -179,12 +217,14 @@ function parseArray(
|
|
|
179
217
|
size = parser.parseSizeGroup(true);
|
|
180
218
|
}
|
|
181
219
|
rowGaps.push(size ? size.value : null);
|
|
220
|
+
endRow();
|
|
182
221
|
|
|
183
222
|
// check for \hline(s) following the row separator
|
|
184
223
|
hLinesBeforeRow.push(getHLines(parser));
|
|
185
224
|
|
|
186
225
|
row = [];
|
|
187
226
|
body.push(row);
|
|
227
|
+
beginRow();
|
|
188
228
|
} else {
|
|
189
229
|
throw new ParseError("Expected & or \\\\ or \\cr or \\end",
|
|
190
230
|
parser.nextToken);
|
|
@@ -207,7 +247,7 @@ function parseArray(
|
|
|
207
247
|
hskipBeforeAndAfter,
|
|
208
248
|
hLinesBeforeRow,
|
|
209
249
|
colSeparationType,
|
|
210
|
-
|
|
250
|
+
tags,
|
|
211
251
|
leqno,
|
|
212
252
|
};
|
|
213
253
|
}
|
|
@@ -339,17 +379,27 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
|
|
339
379
|
let colSep;
|
|
340
380
|
let colDescrNum;
|
|
341
381
|
|
|
342
|
-
const
|
|
343
|
-
if (group.
|
|
344
|
-
// An environment with automatic equation numbers.
|
|
345
|
-
// Create node(s)
|
|
382
|
+
const tagSpans = [];
|
|
383
|
+
if (group.tags && group.tags.some((tag) => tag)) {
|
|
384
|
+
// An environment with manual tags and/or automatic equation numbers.
|
|
385
|
+
// Create node(s), the latter of which trigger CSS counter increment.
|
|
346
386
|
for (r = 0; r < nr; ++r) {
|
|
347
387
|
const rw = body[r];
|
|
348
388
|
const shift = rw.pos - offset;
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
389
|
+
const tag = group.tags[r];
|
|
390
|
+
let tagSpan;
|
|
391
|
+
if (tag === true) { // automatic numbering
|
|
392
|
+
tagSpan = buildCommon.makeSpan(["eqn-num"], [], options);
|
|
393
|
+
} else if (tag === false) {
|
|
394
|
+
// \nonumber/\notag or starred environment
|
|
395
|
+
tagSpan = buildCommon.makeSpan([], [], options);
|
|
396
|
+
} else { // manual \tag
|
|
397
|
+
tagSpan = buildCommon.makeSpan([],
|
|
398
|
+
html.buildExpression(tag, options, true), options);
|
|
399
|
+
}
|
|
400
|
+
tagSpan.depth = rw.depth;
|
|
401
|
+
tagSpan.height = rw.height;
|
|
402
|
+
tagSpans.push({type: "elem", elem: tagSpan, shift});
|
|
353
403
|
}
|
|
354
404
|
}
|
|
355
405
|
|
|
@@ -465,12 +515,12 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
|
|
465
515
|
}, options);
|
|
466
516
|
}
|
|
467
517
|
|
|
468
|
-
if (
|
|
518
|
+
if (tagSpans.length === 0) {
|
|
469
519
|
return buildCommon.makeSpan(["mord"], [body], options);
|
|
470
520
|
} else {
|
|
471
521
|
let eqnNumCol = buildCommon.makeVList({
|
|
472
522
|
positionType: "individualShift",
|
|
473
|
-
children:
|
|
523
|
+
children: tagSpans,
|
|
474
524
|
}, options);
|
|
475
525
|
eqnNumCol = buildCommon.makeSpan(["tag"], [eqnNumCol], options);
|
|
476
526
|
return buildCommon.makeFragment([body, eqnNumCol]);
|
|
@@ -494,7 +544,7 @@ const mathmlBuilder: MathMLBuilder<"array"> = function(group, options) {
|
|
|
494
544
|
row.push(new mathMLTree.MathNode("mtd",
|
|
495
545
|
[mml.buildGroup(rw[j], options)]));
|
|
496
546
|
}
|
|
497
|
-
if (group.
|
|
547
|
+
if (group.tags && group.tags[i]) {
|
|
498
548
|
row.unshift(glue);
|
|
499
549
|
row.push(glue);
|
|
500
550
|
if (group.leqno) {
|
|
@@ -631,14 +681,15 @@ const alignedHandler = function(context, args) {
|
|
|
631
681
|
}
|
|
632
682
|
const cols = [];
|
|
633
683
|
const separationType = context.envName.indexOf("at") > -1 ? "alignat" : "align";
|
|
684
|
+
const isSplit = context.envName === "split";
|
|
634
685
|
const res = parseArray(context.parser,
|
|
635
686
|
{
|
|
636
687
|
cols,
|
|
637
688
|
addJot: true,
|
|
638
|
-
|
|
689
|
+
autoTag: isSplit ? undefined : getAutoTag(context.envName),
|
|
639
690
|
emptySingleRow: true,
|
|
640
691
|
colSeparationType: separationType,
|
|
641
|
-
maxNumCols:
|
|
692
|
+
maxNumCols: isSplit ? 2 : undefined,
|
|
642
693
|
leqno: context.parser.settings.leqno,
|
|
643
694
|
},
|
|
644
695
|
"display"
|
|
@@ -984,7 +1035,7 @@ defineEnvironment({
|
|
|
984
1035
|
}],
|
|
985
1036
|
addJot: true,
|
|
986
1037
|
colSeparationType: "gather",
|
|
987
|
-
|
|
1038
|
+
autoTag: getAutoTag(context.envName),
|
|
988
1039
|
emptySingleRow: true,
|
|
989
1040
|
leqno: context.parser.settings.leqno,
|
|
990
1041
|
};
|
|
@@ -1017,7 +1068,7 @@ defineEnvironment({
|
|
|
1017
1068
|
handler(context) {
|
|
1018
1069
|
validateAmsEnvironmentContext(context);
|
|
1019
1070
|
const res = {
|
|
1020
|
-
|
|
1071
|
+
autoTag: getAutoTag(context.envName),
|
|
1021
1072
|
emptySingleRow: true,
|
|
1022
1073
|
singleRow: true,
|
|
1023
1074
|
maxNumCols: 1,
|
|
@@ -1043,6 +1094,9 @@ defineEnvironment({
|
|
|
1043
1094
|
mathmlBuilder,
|
|
1044
1095
|
});
|
|
1045
1096
|
|
|
1097
|
+
defineMacro("\\nonumber", "\\gdef\\@eqnsw{0}");
|
|
1098
|
+
defineMacro("\\notag", "\\nonumber");
|
|
1099
|
+
|
|
1046
1100
|
// Catch \hline outside array environment
|
|
1047
1101
|
defineFunction({
|
|
1048
1102
|
type: "text", // Doesn't matter what this is.
|
package/src/parseNode.js
CHANGED
|
@@ -39,7 +39,8 @@ type ParseNodeTypes = {
|
|
|
39
39
|
body: AnyParseNode[][], // List of rows in the (2D) array.
|
|
40
40
|
rowGaps: (?Measurement)[],
|
|
41
41
|
hLinesBeforeRow: Array<boolean[]>,
|
|
42
|
-
|
|
42
|
+
// Whether each row should be automatically numbered, or an explicit tag
|
|
43
|
+
tags?: (boolean | AnyParseNode[])[],
|
|
43
44
|
leqno?: boolean,
|
|
44
45
|
isCD?: boolean,
|
|
45
46
|
|},
|
package/src/parseTree.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
import Parser from "./Parser";
|
|
8
8
|
import ParseError from "./ParseError";
|
|
9
|
+
import {Token} from "./Token";
|
|
9
10
|
|
|
10
11
|
import type Settings from "./Settings";
|
|
11
12
|
import type {AnyParseNode} from "./parseNode";
|
|
@@ -34,12 +35,11 @@ const parseTree = function(toParse: string, settings: Settings): AnyParseNode[]
|
|
|
34
35
|
if (!settings.displayMode) {
|
|
35
36
|
throw new ParseError("\\tag works only in display equations");
|
|
36
37
|
}
|
|
37
|
-
parser.gullet.feed("\\df@tag");
|
|
38
38
|
tree = [{
|
|
39
39
|
type: "tag",
|
|
40
40
|
mode: "text",
|
|
41
41
|
body: tree,
|
|
42
|
-
tag: parser.
|
|
42
|
+
tag: parser.subparse([new Token("\\df@tag")]),
|
|
43
43
|
}];
|
|
44
44
|
}
|
|
45
45
|
|