mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-07 04:08:43 +00:00
Flatten "styling", "text", and "array" ParseNodes. (#1559)
* Flatten "styling" ParseNode. * Flatten "text" ParseNode. * Flatten "array" ParseNode.
This commit is contained in:
@@ -319,10 +319,7 @@ export default class Parser {
|
|||||||
const textNode = {
|
const textNode = {
|
||||||
type: "text",
|
type: "text",
|
||||||
mode: this.mode,
|
mode: this.mode,
|
||||||
value: {
|
body: textordArray,
|
||||||
type: "text",
|
|
||||||
body: textordArray,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const colorNode = {
|
const colorNode = {
|
||||||
|
@@ -171,8 +171,7 @@ export const buildExpression = function(
|
|||||||
} else if (node.type === "sizing") {
|
} else if (node.type === "sizing") {
|
||||||
glueOptions = options.havingSize(node.size);
|
glueOptions = options.havingSize(node.size);
|
||||||
} else if (node.type === "styling") {
|
} else if (node.type === "styling") {
|
||||||
glueOptions = options.havingStyle(
|
glueOptions = options.havingStyle(styleMap[node.style]);
|
||||||
styleMap[node.value.style]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -16,39 +16,15 @@ import type Parser from "../Parser";
|
|||||||
import type {ParseNode, AnyParseNode} from "../parseNode";
|
import type {ParseNode, AnyParseNode} from "../parseNode";
|
||||||
import type {StyleStr} from "../types";
|
import type {StyleStr} from "../types";
|
||||||
import type {HtmlBuilder, MathMLBuilder} from "../defineFunction";
|
import type {HtmlBuilder, MathMLBuilder} from "../defineFunction";
|
||||||
import type {Measurement} from "../units";
|
|
||||||
|
|
||||||
// Data stored in the ParseNode associated with the environment.
|
// Data stored in the ParseNode associated with the environment.
|
||||||
type AlignSpec = { type: "separator", separator: string } | {
|
export type AlignSpec = { type: "separator", separator: string } | {
|
||||||
type: "align",
|
type: "align",
|
||||||
align: string,
|
align: string,
|
||||||
pregap?: number,
|
pregap?: number,
|
||||||
postgap?: number,
|
postgap?: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ArrayEnvNodeData = {|
|
|
||||||
type: "array",
|
|
||||||
hskipBeforeAndAfter?: boolean,
|
|
||||||
addJot?: boolean,
|
|
||||||
cols?: AlignSpec[],
|
|
||||||
arraystretch: number,
|
|
||||||
body: AnyParseNode[][], // List of rows in the (2D) array.
|
|
||||||
rowGaps: (?Measurement)[],
|
|
||||||
hLinesBeforeRow: Array<boolean[]>,
|
|
||||||
|};
|
|
||||||
// Same as above but with some fields not yet filled.
|
|
||||||
type ArrayEnvNodeDataIncomplete = {|
|
|
||||||
type: "array",
|
|
||||||
hskipBeforeAndAfter?: boolean,
|
|
||||||
addJot?: boolean,
|
|
||||||
cols?: AlignSpec[],
|
|
||||||
// Before these fields are filled.
|
|
||||||
arraystretch?: number,
|
|
||||||
body?: AnyParseNode[][],
|
|
||||||
rowGaps?: (?Measurement)[],
|
|
||||||
hLinesBeforeRow?: Array<boolean[]>,
|
|
||||||
|};
|
|
||||||
|
|
||||||
function getHLines(parser: Parser): boolean[] {
|
function getHLines(parser: Parser): boolean[] {
|
||||||
// Return an array. The array length = number of hlines.
|
// Return an array. The array length = number of hlines.
|
||||||
// Each element in the array tells if the line is dashed.
|
// Each element in the array tells if the line is dashed.
|
||||||
@@ -72,7 +48,12 @@ function getHLines(parser: Parser): boolean[] {
|
|||||||
*/
|
*/
|
||||||
function parseArray(
|
function parseArray(
|
||||||
parser: Parser,
|
parser: Parser,
|
||||||
result: ArrayEnvNodeDataIncomplete,
|
{hskipBeforeAndAfter, addJot, cols, arraystretch}: {|
|
||||||
|
hskipBeforeAndAfter?: boolean,
|
||||||
|
addJot?: boolean,
|
||||||
|
cols?: AlignSpec[],
|
||||||
|
arraystretch?: number,
|
||||||
|
|},
|
||||||
style: StyleStr,
|
style: StyleStr,
|
||||||
): ParseNode<"array"> {
|
): ParseNode<"array"> {
|
||||||
// Parse body of array with \\ temporarily mapped to \cr
|
// Parse body of array with \\ temporarily mapped to \cr
|
||||||
@@ -80,15 +61,15 @@ function parseArray(
|
|||||||
parser.gullet.macros.set("\\\\", "\\cr");
|
parser.gullet.macros.set("\\\\", "\\cr");
|
||||||
|
|
||||||
// Get current arraystretch if it's not set by the environment
|
// Get current arraystretch if it's not set by the environment
|
||||||
if (!result.arraystretch) {
|
if (!arraystretch) {
|
||||||
const arraystretch = parser.gullet.expandMacroAsText("\\arraystretch");
|
const stretch = parser.gullet.expandMacroAsText("\\arraystretch");
|
||||||
if (arraystretch == null) {
|
if (stretch == null) {
|
||||||
// Default \arraystretch from lttab.dtx
|
// Default \arraystretch from lttab.dtx
|
||||||
result.arraystretch = 1;
|
arraystretch = 1;
|
||||||
} else {
|
} else {
|
||||||
result.arraystretch = parseFloat(arraystretch);
|
arraystretch = parseFloat(stretch);
|
||||||
if (!result.arraystretch || result.arraystretch < 0) {
|
if (!arraystretch || arraystretch < 0) {
|
||||||
throw new ParseError(`Invalid \\arraystretch: ${arraystretch}`);
|
throw new ParseError(`Invalid \\arraystretch: ${stretch}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,11 +93,8 @@ function parseArray(
|
|||||||
cell = {
|
cell = {
|
||||||
type: "styling",
|
type: "styling",
|
||||||
mode: parser.mode,
|
mode: parser.mode,
|
||||||
value: {
|
style,
|
||||||
type: "styling",
|
body: [cell],
|
||||||
style: style,
|
|
||||||
value: [cell],
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
row.push(cell);
|
row.push(cell);
|
||||||
@@ -128,7 +106,7 @@ function parseArray(
|
|||||||
// the last line is empty.
|
// the last line is empty.
|
||||||
// NOTE: Currently, `cell` is the last item added into `row`.
|
// NOTE: Currently, `cell` is the last item added into `row`.
|
||||||
if (row.length === 1 && cell.type === "styling" &&
|
if (row.length === 1 && cell.type === "styling" &&
|
||||||
cell.value.value[0].value.length === 0) {
|
cell.body[0].value.length === 0) {
|
||||||
body.pop();
|
body.pop();
|
||||||
}
|
}
|
||||||
if (hLinesBeforeRow.length < body.length + 1) {
|
if (hLinesBeforeRow.length < body.length + 1) {
|
||||||
@@ -152,16 +130,17 @@ function parseArray(
|
|||||||
parser.nextToken);
|
parser.nextToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
result.body = body;
|
|
||||||
result.rowGaps = rowGaps;
|
|
||||||
result.hLinesBeforeRow = hLinesBeforeRow;
|
|
||||||
// $FlowFixMe: The required fields were added immediately above.
|
|
||||||
const res: ArrayEnvNodeData = result;
|
|
||||||
parser.gullet.endGroup();
|
parser.gullet.endGroup();
|
||||||
return {
|
return {
|
||||||
type: "array",
|
type: "array",
|
||||||
mode: parser.mode,
|
mode: parser.mode,
|
||||||
value: res,
|
addJot,
|
||||||
|
arraystretch,
|
||||||
|
body,
|
||||||
|
cols,
|
||||||
|
rowGaps,
|
||||||
|
hskipBeforeAndAfter,
|
||||||
|
hLinesBeforeRow,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,8 +165,8 @@ type Outrow = {
|
|||||||
const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
||||||
let r;
|
let r;
|
||||||
let c;
|
let c;
|
||||||
const nr = group.value.body.length;
|
const nr = group.body.length;
|
||||||
const hLinesBeforeRow = group.value.hLinesBeforeRow;
|
const hLinesBeforeRow = group.hLinesBeforeRow;
|
||||||
let nc = 0;
|
let nc = 0;
|
||||||
let body = new Array(nr);
|
let body = new Array(nr);
|
||||||
const hlines = [];
|
const hlines = [];
|
||||||
@@ -201,7 +180,7 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
|||||||
// Default \jot from ltmath.dtx
|
// Default \jot from ltmath.dtx
|
||||||
// TODO(edemaine): allow overriding \jot via \setlength (#687)
|
// TODO(edemaine): allow overriding \jot via \setlength (#687)
|
||||||
const jot = 3 * pt;
|
const jot = 3 * pt;
|
||||||
const arrayskip = group.value.arraystretch * baselineskip;
|
const arrayskip = group.arraystretch * baselineskip;
|
||||||
const arstrutHeight = 0.7 * arrayskip; // \strutbox in ltfsstrc.dtx and
|
const arstrutHeight = 0.7 * arrayskip; // \strutbox in ltfsstrc.dtx and
|
||||||
const arstrutDepth = 0.3 * arrayskip; // \@arstrutbox in lttab.dtx
|
const arstrutDepth = 0.3 * arrayskip; // \@arstrutbox in lttab.dtx
|
||||||
|
|
||||||
@@ -218,8 +197,8 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
|||||||
}
|
}
|
||||||
setHLinePos(hLinesBeforeRow[0]);
|
setHLinePos(hLinesBeforeRow[0]);
|
||||||
|
|
||||||
for (r = 0; r < group.value.body.length; ++r) {
|
for (r = 0; r < group.body.length; ++r) {
|
||||||
const inrow = group.value.body[r];
|
const inrow = group.body[r];
|
||||||
let height = arstrutHeight; // \@array adds an \@arstrut
|
let height = arstrutHeight; // \@array adds an \@arstrut
|
||||||
let depth = arstrutDepth; // to each tow (via the template)
|
let depth = arstrutDepth; // to each tow (via the template)
|
||||||
|
|
||||||
@@ -239,7 +218,7 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
|||||||
outrow[c] = elt;
|
outrow[c] = elt;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rowGap = group.value.rowGaps[r];
|
const rowGap = group.rowGaps[r];
|
||||||
let gap = 0;
|
let gap = 0;
|
||||||
if (rowGap) {
|
if (rowGap) {
|
||||||
gap = calculateSize(rowGap, options);
|
gap = calculateSize(rowGap, options);
|
||||||
@@ -254,7 +233,7 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
|||||||
// In AMS multiline environments such as aligned and gathered, rows
|
// In AMS multiline environments such as aligned and gathered, rows
|
||||||
// correspond to lines that have additional \jot added to the
|
// correspond to lines that have additional \jot added to the
|
||||||
// \baselineskip via \openup.
|
// \baselineskip via \openup.
|
||||||
if (group.value.addJot) {
|
if (group.addJot) {
|
||||||
depth += jot;
|
depth += jot;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,7 +249,7 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const offset = totalHeight / 2 + options.fontMetrics().axisHeight;
|
const offset = totalHeight / 2 + options.fontMetrics().axisHeight;
|
||||||
const colDescriptions = group.value.cols || [];
|
const colDescriptions = group.cols || [];
|
||||||
const cols = [];
|
const cols = [];
|
||||||
let colSep;
|
let colSep;
|
||||||
let colDescrNum;
|
let colDescrNum;
|
||||||
@@ -326,7 +305,7 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let sepwidth;
|
let sepwidth;
|
||||||
if (c > 0 || group.value.hskipBeforeAndAfter) {
|
if (c > 0 || group.hskipBeforeAndAfter) {
|
||||||
sepwidth = utils.deflt(colDescr.pregap, arraycolsep);
|
sepwidth = utils.deflt(colDescr.pregap, arraycolsep);
|
||||||
if (sepwidth !== 0) {
|
if (sepwidth !== 0) {
|
||||||
colSep = buildCommon.makeSpan(["arraycolsep"], []);
|
colSep = buildCommon.makeSpan(["arraycolsep"], []);
|
||||||
@@ -357,7 +336,7 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
|||||||
[col]);
|
[col]);
|
||||||
cols.push(col);
|
cols.push(col);
|
||||||
|
|
||||||
if (c < nc - 1 || group.value.hskipBeforeAndAfter) {
|
if (c < nc - 1 || group.hskipBeforeAndAfter) {
|
||||||
sepwidth = utils.deflt(colDescr.postgap, arraycolsep);
|
sepwidth = utils.deflt(colDescr.postgap, arraycolsep);
|
||||||
if (sepwidth !== 0) {
|
if (sepwidth !== 0) {
|
||||||
colSep = buildCommon.makeSpan(["arraycolsep"], []);
|
colSep = buildCommon.makeSpan(["arraycolsep"], []);
|
||||||
@@ -393,7 +372,7 @@ const htmlBuilder: HtmlBuilder<"array"> = function(group, options) {
|
|||||||
|
|
||||||
const mathmlBuilder: MathMLBuilder<"array"> = function(group, options) {
|
const mathmlBuilder: MathMLBuilder<"array"> = function(group, options) {
|
||||||
return new mathMLTree.MathNode(
|
return new mathMLTree.MathNode(
|
||||||
"mtable", group.value.body.map(function(row) {
|
"mtable", group.body.map(function(row) {
|
||||||
return new mathMLTree.MathNode(
|
return new mathMLTree.MathNode(
|
||||||
"mtr", row.map(function(cell) {
|
"mtr", row.map(function(cell) {
|
||||||
return new mathMLTree.MathNode(
|
return new mathMLTree.MathNode(
|
||||||
@@ -405,12 +384,7 @@ const mathmlBuilder: MathMLBuilder<"array"> = function(group, options) {
|
|||||||
// Convenience function for aligned and alignedat environments.
|
// Convenience function for aligned and alignedat environments.
|
||||||
const alignedHandler = function(context, args) {
|
const alignedHandler = function(context, args) {
|
||||||
const cols = [];
|
const cols = [];
|
||||||
let res = {
|
const res = parseArray(context.parser, {cols, addJot: true}, "display");
|
||||||
type: "array",
|
|
||||||
cols,
|
|
||||||
addJot: true,
|
|
||||||
};
|
|
||||||
res = parseArray(context.parser, res, "display");
|
|
||||||
|
|
||||||
// Determining number of columns.
|
// Determining number of columns.
|
||||||
// 1. If the first argument is given, we use it as a number of columns,
|
// 1. If the first argument is given, we use it as a number of columns,
|
||||||
@@ -439,11 +413,11 @@ const alignedHandler = function(context, args) {
|
|||||||
numCols = numMaths * 2;
|
numCols = numMaths * 2;
|
||||||
}
|
}
|
||||||
const isAligned = !numCols;
|
const isAligned = !numCols;
|
||||||
res.value.body.forEach(function(row) {
|
res.body.forEach(function(row) {
|
||||||
for (let i = 1; i < row.length; i += 2) {
|
for (let i = 1; i < row.length; i += 2) {
|
||||||
// Modify ordgroup node within styling node
|
// Modify ordgroup node within styling node
|
||||||
const styling = assertNodeType(row[i], "styling");
|
const styling = assertNodeType(row[i], "styling");
|
||||||
const ordgroup = assertNodeType(styling.value.value[0], "ordgroup");
|
const ordgroup = assertNodeType(styling.body[0], "ordgroup");
|
||||||
ordgroup.value.unshift(emptyGroup);
|
ordgroup.value.unshift(emptyGroup);
|
||||||
}
|
}
|
||||||
if (!isAligned) { // Case 1
|
if (!isAligned) { // Case 1
|
||||||
@@ -519,13 +493,11 @@ defineEnvironment({
|
|||||||
}
|
}
|
||||||
throw new ParseError("Unknown column alignment: " + ca, nde);
|
throw new ParseError("Unknown column alignment: " + ca, nde);
|
||||||
});
|
});
|
||||||
let res = {
|
const res = {
|
||||||
type: "array",
|
cols,
|
||||||
cols: cols,
|
|
||||||
hskipBeforeAndAfter: true, // \@preamble in lttab.dtx
|
hskipBeforeAndAfter: true, // \@preamble in lttab.dtx
|
||||||
};
|
};
|
||||||
res = parseArray(context.parser, res, dCellStyle(context.envName));
|
return parseArray(context.parser, res, dCellStyle(context.envName));
|
||||||
return res;
|
|
||||||
},
|
},
|
||||||
htmlBuilder,
|
htmlBuilder,
|
||||||
mathmlBuilder,
|
mathmlBuilder,
|
||||||
@@ -555,10 +527,8 @@ defineEnvironment({
|
|||||||
"vmatrix": ["|", "|"],
|
"vmatrix": ["|", "|"],
|
||||||
"Vmatrix": ["\\Vert", "\\Vert"],
|
"Vmatrix": ["\\Vert", "\\Vert"],
|
||||||
}[context.envName];
|
}[context.envName];
|
||||||
const payload = {
|
// \hskip -\arraycolsep in amsmath
|
||||||
type: "array",
|
const payload = {hskipBeforeAndAfter: false};
|
||||||
hskipBeforeAndAfter: false, // \hskip -\arraycolsep in amsmath
|
|
||||||
};
|
|
||||||
const res: ParseNode<"array"> =
|
const res: ParseNode<"array"> =
|
||||||
parseArray(context.parser, payload, dCellStyle(context.envName));
|
parseArray(context.parser, payload, dCellStyle(context.envName));
|
||||||
return delimiters ? {
|
return delimiters ? {
|
||||||
@@ -589,7 +559,6 @@ defineEnvironment({
|
|||||||
},
|
},
|
||||||
handler(context) {
|
handler(context) {
|
||||||
const payload = {
|
const payload = {
|
||||||
type: "array",
|
|
||||||
arraystretch: 1.2,
|
arraystretch: 1.2,
|
||||||
cols: [{
|
cols: [{
|
||||||
type: "align",
|
type: "align",
|
||||||
@@ -645,17 +614,15 @@ defineEnvironment({
|
|||||||
props: {
|
props: {
|
||||||
numArgs: 0,
|
numArgs: 0,
|
||||||
},
|
},
|
||||||
handler: function(context) {
|
handler(context) {
|
||||||
let res = {
|
const res = {
|
||||||
type: "array",
|
|
||||||
cols: [{
|
cols: [{
|
||||||
type: "align",
|
type: "align",
|
||||||
align: "c",
|
align: "c",
|
||||||
}],
|
}],
|
||||||
addJot: true,
|
addJot: true,
|
||||||
};
|
};
|
||||||
res = parseArray(context.parser, res, "display");
|
return parseArray(context.parser, res, "display");
|
||||||
return res;
|
|
||||||
},
|
},
|
||||||
htmlBuilder,
|
htmlBuilder,
|
||||||
mathmlBuilder,
|
mathmlBuilder,
|
||||||
|
@@ -62,11 +62,8 @@ defineFunction({
|
|||||||
const body = {
|
const body = {
|
||||||
type: "text",
|
type: "text",
|
||||||
mode: parser.mode,
|
mode: parser.mode,
|
||||||
value: {
|
font: "\\texttt",
|
||||||
type: "text",
|
body: chars,
|
||||||
font: "\\texttt",
|
|
||||||
body: chars,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
type: "href",
|
type: "href",
|
||||||
|
@@ -25,11 +25,8 @@ defineFunction({
|
|||||||
return {
|
return {
|
||||||
type: "styling",
|
type: "styling",
|
||||||
mode: parser.mode,
|
mode: parser.mode,
|
||||||
value: {
|
style: "text",
|
||||||
type: "styling",
|
body,
|
||||||
style: "text",
|
|
||||||
value: body,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@@ -31,11 +31,8 @@ defineFunction({
|
|||||||
const text = {
|
const text = {
|
||||||
type: "text",
|
type: "text",
|
||||||
mode: group.mode,
|
mode: group.mode,
|
||||||
value: {
|
body: ordargument(group.body),
|
||||||
type: "text",
|
font: "mathrm", // simulate \textrm
|
||||||
body: ordargument(group.body),
|
|
||||||
font: "mathrm", // simulate \textrm
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
const sizedText = {
|
const sizedText = {
|
||||||
type: "sizing",
|
type: "sizing",
|
||||||
|
@@ -23,7 +23,7 @@ defineFunction({
|
|||||||
numArgs: 0,
|
numArgs: 0,
|
||||||
allowedInText: true,
|
allowedInText: true,
|
||||||
},
|
},
|
||||||
handler: ({breakOnTokenText, funcName, parser}, args) => {
|
handler({breakOnTokenText, funcName, parser}, args) {
|
||||||
// parse out the implicit body
|
// parse out the implicit body
|
||||||
parser.consumeSpaces();
|
parser.consumeSpaces();
|
||||||
const body = parser.parseExpression(true, breakOnTokenText);
|
const body = parser.parseExpression(true, breakOnTokenText);
|
||||||
@@ -35,22 +35,19 @@ defineFunction({
|
|||||||
return {
|
return {
|
||||||
type: "styling",
|
type: "styling",
|
||||||
mode: parser.mode,
|
mode: parser.mode,
|
||||||
value: {
|
// Figure out what style to use by pulling out the style from
|
||||||
type: "styling",
|
// the function name
|
||||||
// Figure out what style to use by pulling out the style from
|
style,
|
||||||
// the function name
|
body,
|
||||||
style,
|
|
||||||
value: body,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
htmlBuilder: (group, options) => {
|
htmlBuilder(group, options) {
|
||||||
// Style changes are handled in the TeXbook on pg. 442, Rule 3.
|
// Style changes are handled in the TeXbook on pg. 442, Rule 3.
|
||||||
const newStyle = styleMap[group.value.style];
|
const newStyle = styleMap[group.style];
|
||||||
const newOptions = options.havingStyle(newStyle).withFont('');
|
const newOptions = options.havingStyle(newStyle).withFont('');
|
||||||
return sizingGroup(group.value.value, newOptions, options);
|
return sizingGroup(group.body, newOptions, options);
|
||||||
},
|
},
|
||||||
mathmlBuilder: (group, options) => {
|
mathmlBuilder(group, options) {
|
||||||
// Figure out what style we're changing to.
|
// Figure out what style we're changing to.
|
||||||
// TODO(kevinb): dedupe this with buildHTML.js
|
// TODO(kevinb): dedupe this with buildHTML.js
|
||||||
// This will be easier of handling of styling nodes is in the same file.
|
// This will be easier of handling of styling nodes is in the same file.
|
||||||
@@ -61,10 +58,10 @@ defineFunction({
|
|||||||
"scriptscript": Style.SCRIPTSCRIPT,
|
"scriptscript": Style.SCRIPTSCRIPT,
|
||||||
};
|
};
|
||||||
|
|
||||||
const newStyle = styleMap[group.value.style];
|
const newStyle = styleMap[group.style];
|
||||||
const newOptions = options.havingStyle(newStyle);
|
const newOptions = options.havingStyle(newStyle);
|
||||||
|
|
||||||
const inner = mml.buildExpression(group.value.value, newOptions);
|
const inner = mml.buildExpression(group.body, newOptions);
|
||||||
|
|
||||||
const node = new mathMLTree.MathNode("mstyle", inner);
|
const node = new mathMLTree.MathNode("mstyle", inner);
|
||||||
|
|
||||||
@@ -75,7 +72,7 @@ defineFunction({
|
|||||||
"scriptscript": ["2", "false"],
|
"scriptscript": ["2", "false"],
|
||||||
};
|
};
|
||||||
|
|
||||||
const attr = styleAttributes[group.value.style];
|
const attr = styleAttributes[group.style];
|
||||||
|
|
||||||
node.setAttribute("scriptlevel", attr[0]);
|
node.setAttribute("scriptlevel", attr[0]);
|
||||||
node.setAttribute("displaystyle", attr[1]);
|
node.setAttribute("displaystyle", attr[1]);
|
||||||
|
@@ -20,7 +20,7 @@ const textFontShapes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const optionsWithFont = (group, options) => {
|
const optionsWithFont = (group, options) => {
|
||||||
const font = group.value.font;
|
const font = group.font;
|
||||||
// Checks if the argument is a font family or a font style.
|
// Checks if the argument is a font family or a font style.
|
||||||
if (!font) {
|
if (!font) {
|
||||||
return options;
|
return options;
|
||||||
@@ -55,21 +55,18 @@ defineFunction({
|
|||||||
return {
|
return {
|
||||||
type: "text",
|
type: "text",
|
||||||
mode: parser.mode,
|
mode: parser.mode,
|
||||||
value: {
|
body: ordargument(body),
|
||||||
type: "text",
|
font: funcName,
|
||||||
body: ordargument(body),
|
|
||||||
font: funcName,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
htmlBuilder(group, options) {
|
htmlBuilder(group, options) {
|
||||||
const newOptions = optionsWithFont(group, options);
|
const newOptions = optionsWithFont(group, options);
|
||||||
const inner = html.buildExpression(group.value.body, newOptions, true);
|
const inner = html.buildExpression(group.body, newOptions, true);
|
||||||
buildCommon.tryCombineChars(inner);
|
buildCommon.tryCombineChars(inner);
|
||||||
return buildCommon.makeSpan(["mord", "text"], inner, newOptions);
|
return buildCommon.makeSpan(["mord", "text"], inner, newOptions);
|
||||||
},
|
},
|
||||||
mathmlBuilder(group, options) {
|
mathmlBuilder(group, options) {
|
||||||
const newOptions = optionsWithFont(group, options);
|
const newOptions = optionsWithFont(group, options);
|
||||||
return mml.buildExpressionRow(group.value.body, newOptions);
|
return mml.buildExpressionRow(group.body, newOptions);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@@ -1,7 +1,7 @@
|
|||||||
// @flow
|
// @flow
|
||||||
import {NON_ATOMS} from "./symbols";
|
import {NON_ATOMS} from "./symbols";
|
||||||
import type SourceLocation from "./SourceLocation";
|
import type SourceLocation from "./SourceLocation";
|
||||||
import type {ArrayEnvNodeData} from "./environments/array";
|
import type {AlignSpec} from "./environments/array";
|
||||||
import type {Atom} from "./symbols";
|
import type {Atom} from "./symbols";
|
||||||
import type {Mode, StyleStr} from "./types";
|
import type {Mode, StyleStr} from "./types";
|
||||||
import type {Token} from "./Token";
|
import type {Token} from "./Token";
|
||||||
@@ -28,7 +28,13 @@ type ParseNodeTypes = {
|
|||||||
type: "array",
|
type: "array",
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
loc?: ?SourceLocation,
|
loc?: ?SourceLocation,
|
||||||
value: ArrayEnvNodeData,
|
hskipBeforeAndAfter?: boolean,
|
||||||
|
addJot?: boolean,
|
||||||
|
cols?: AlignSpec[],
|
||||||
|
arraystretch: number,
|
||||||
|
body: AnyParseNode[][], // List of rows in the (2D) array.
|
||||||
|
rowGaps: (?Measurement)[],
|
||||||
|
hLinesBeforeRow: Array<boolean[]>,
|
||||||
|},
|
|},
|
||||||
"color": {|
|
"color": {|
|
||||||
type: "color",
|
type: "color",
|
||||||
@@ -85,11 +91,8 @@ type ParseNodeTypes = {
|
|||||||
type: "styling",
|
type: "styling",
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
loc?: ?SourceLocation,
|
loc?: ?SourceLocation,
|
||||||
value: {|
|
style: StyleStr,
|
||||||
type: "styling",
|
body: AnyParseNode[],
|
||||||
style: StyleStr,
|
|
||||||
value: AnyParseNode[],
|
|
||||||
|},
|
|
||||||
|},
|
|},
|
||||||
"supsub": {|
|
"supsub": {|
|
||||||
type: "supsub",
|
type: "supsub",
|
||||||
@@ -110,11 +113,8 @@ type ParseNodeTypes = {
|
|||||||
type: "text",
|
type: "text",
|
||||||
mode: Mode,
|
mode: Mode,
|
||||||
loc?: ?SourceLocation,
|
loc?: ?SourceLocation,
|
||||||
value: {|
|
body: AnyParseNode[],
|
||||||
type: "text",
|
font?: string,
|
||||||
body: AnyParseNode[],
|
|
||||||
font?: string,
|
|
||||||
|},
|
|
||||||
|},
|
|},
|
||||||
"url": {|
|
"url": {|
|
||||||
type: "url",
|
type: "url",
|
||||||
|
@@ -4,145 +4,130 @@ exports[`A begin/end parser should grab \\arraystretch 1`] = `
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"mode": "math",
|
"arraystretch": 1.5,
|
||||||
"value": {
|
"body": [
|
||||||
"type": "array",
|
[
|
||||||
"arraystretch": 1.5,
|
{
|
||||||
"body": [
|
"type": "styling",
|
||||||
[
|
"body": [
|
||||||
{
|
{
|
||||||
"type": "styling",
|
"type": "ordgroup",
|
||||||
"mode": "math",
|
"mode": "math",
|
||||||
"value": {
|
|
||||||
"type": "styling",
|
|
||||||
"style": "text",
|
|
||||||
"value": [
|
"value": [
|
||||||
{
|
{
|
||||||
"type": "ordgroup",
|
"type": "mathord",
|
||||||
|
"loc": {
|
||||||
|
"end": 37,
|
||||||
|
"lexer": {
|
||||||
|
"input": "\\\\def\\\\arraystretch{1.5}\\\\begin{matrix}a&b\\\\\\\\c&d\\\\end{matrix}",
|
||||||
|
"lastIndex": 56
|
||||||
|
},
|
||||||
|
"start": 36
|
||||||
|
},
|
||||||
"mode": "math",
|
"mode": "math",
|
||||||
"value": [
|
"value": "a"
|
||||||
{
|
|
||||||
"type": "mathord",
|
|
||||||
"loc": {
|
|
||||||
"end": 37,
|
|
||||||
"lexer": {
|
|
||||||
"input": "\\\\def\\\\arraystretch{1.5}\\\\begin{matrix}a&b\\\\\\\\c&d\\\\end{matrix}",
|
|
||||||
"lastIndex": 56
|
|
||||||
},
|
|
||||||
"start": 36
|
|
||||||
},
|
|
||||||
"mode": "math",
|
|
||||||
"value": "a"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
],
|
||||||
{
|
"mode": "math",
|
||||||
"type": "styling",
|
"style": "text"
|
||||||
"mode": "math",
|
},
|
||||||
"value": {
|
{
|
||||||
"type": "styling",
|
"type": "styling",
|
||||||
"style": "text",
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ordgroup",
|
||||||
|
"mode": "math",
|
||||||
"value": [
|
"value": [
|
||||||
{
|
{
|
||||||
"type": "ordgroup",
|
"type": "mathord",
|
||||||
|
"loc": {
|
||||||
|
"end": 39,
|
||||||
|
"lexer": {
|
||||||
|
"input": "\\\\def\\\\arraystretch{1.5}\\\\begin{matrix}a&b\\\\\\\\c&d\\\\end{matrix}",
|
||||||
|
"lastIndex": 56
|
||||||
|
},
|
||||||
|
"start": 38
|
||||||
|
},
|
||||||
"mode": "math",
|
"mode": "math",
|
||||||
"value": [
|
"value": "b"
|
||||||
{
|
|
||||||
"type": "mathord",
|
|
||||||
"loc": {
|
|
||||||
"end": 39,
|
|
||||||
"lexer": {
|
|
||||||
"input": "\\\\def\\\\arraystretch{1.5}\\\\begin{matrix}a&b\\\\\\\\c&d\\\\end{matrix}",
|
|
||||||
"lastIndex": 56
|
|
||||||
},
|
|
||||||
"start": 38
|
|
||||||
},
|
|
||||||
"mode": "math",
|
|
||||||
"value": "b"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
],
|
||||||
],
|
"mode": "math",
|
||||||
[
|
"style": "text"
|
||||||
{
|
}
|
||||||
"type": "styling",
|
|
||||||
"mode": "math",
|
|
||||||
"value": {
|
|
||||||
"type": "styling",
|
|
||||||
"style": "text",
|
|
||||||
"value": [
|
|
||||||
{
|
|
||||||
"type": "ordgroup",
|
|
||||||
"mode": "math",
|
|
||||||
"value": [
|
|
||||||
{
|
|
||||||
"type": "mathord",
|
|
||||||
"loc": {
|
|
||||||
"end": 42,
|
|
||||||
"lexer": {
|
|
||||||
"input": "\\\\def\\\\arraystretch{1.5}\\\\begin{matrix}a&b\\\\\\\\c&d\\\\end{matrix}",
|
|
||||||
"lastIndex": 56
|
|
||||||
},
|
|
||||||
"start": 41
|
|
||||||
},
|
|
||||||
"mode": "math",
|
|
||||||
"value": "c"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"type": "styling",
|
|
||||||
"mode": "math",
|
|
||||||
"value": {
|
|
||||||
"type": "styling",
|
|
||||||
"style": "text",
|
|
||||||
"value": [
|
|
||||||
{
|
|
||||||
"type": "ordgroup",
|
|
||||||
"mode": "math",
|
|
||||||
"value": [
|
|
||||||
{
|
|
||||||
"type": "mathord",
|
|
||||||
"loc": {
|
|
||||||
"end": 44,
|
|
||||||
"lexer": {
|
|
||||||
"input": "\\\\def\\\\arraystretch{1.5}\\\\begin{matrix}a&b\\\\\\\\c&d\\\\end{matrix}",
|
|
||||||
"lastIndex": 56
|
|
||||||
},
|
|
||||||
"start": 43
|
|
||||||
},
|
|
||||||
"mode": "math",
|
|
||||||
"value": "d"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
],
|
],
|
||||||
"hLinesBeforeRow": [
|
[
|
||||||
[
|
{
|
||||||
],
|
"type": "styling",
|
||||||
[
|
"body": [
|
||||||
],
|
{
|
||||||
[
|
"type": "ordgroup",
|
||||||
]
|
"mode": "math",
|
||||||
],
|
"value": [
|
||||||
"hskipBeforeAndAfter": false,
|
{
|
||||||
"rowGaps": [
|
"type": "mathord",
|
||||||
null
|
"loc": {
|
||||||
|
"end": 42,
|
||||||
|
"lexer": {
|
||||||
|
"input": "\\\\def\\\\arraystretch{1.5}\\\\begin{matrix}a&b\\\\\\\\c&d\\\\end{matrix}",
|
||||||
|
"lastIndex": 56
|
||||||
|
},
|
||||||
|
"start": 41
|
||||||
|
},
|
||||||
|
"mode": "math",
|
||||||
|
"value": "c"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mode": "math",
|
||||||
|
"style": "text"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "styling",
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "ordgroup",
|
||||||
|
"mode": "math",
|
||||||
|
"value": [
|
||||||
|
{
|
||||||
|
"type": "mathord",
|
||||||
|
"loc": {
|
||||||
|
"end": 44,
|
||||||
|
"lexer": {
|
||||||
|
"input": "\\\\def\\\\arraystretch{1.5}\\\\begin{matrix}a&b\\\\\\\\c&d\\\\end{matrix}",
|
||||||
|
"lastIndex": 56
|
||||||
|
},
|
||||||
|
"start": 43
|
||||||
|
},
|
||||||
|
"mode": "math",
|
||||||
|
"value": "d"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mode": "math",
|
||||||
|
"style": "text"
|
||||||
|
}
|
||||||
]
|
]
|
||||||
}
|
],
|
||||||
|
"hLinesBeforeRow": [
|
||||||
|
[
|
||||||
|
],
|
||||||
|
[
|
||||||
|
],
|
||||||
|
[
|
||||||
|
]
|
||||||
|
],
|
||||||
|
"hskipBeforeAndAfter": false,
|
||||||
|
"mode": "math",
|
||||||
|
"rowGaps": [
|
||||||
|
null
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
`;
|
`;
|
||||||
@@ -660,18 +645,15 @@ exports[`An implicit group parser within optional groups should work style comma
|
|||||||
"value": [
|
"value": [
|
||||||
{
|
{
|
||||||
"type": "styling",
|
"type": "styling",
|
||||||
|
"body": [
|
||||||
|
{
|
||||||
|
"type": "textord",
|
||||||
|
"mode": "math",
|
||||||
|
"value": "3"
|
||||||
|
}
|
||||||
|
],
|
||||||
"mode": "math",
|
"mode": "math",
|
||||||
"value": {
|
"style": "text"
|
||||||
"type": "styling",
|
|
||||||
"style": "text",
|
|
||||||
"value": [
|
|
||||||
{
|
|
||||||
"type": "textord",
|
|
||||||
"mode": "math",
|
|
||||||
"value": "3"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@@ -666,12 +666,12 @@ describe("A text parser", function() {
|
|||||||
const parse = getParsed(textExpression)[0];
|
const parse = getParsed(textExpression)[0];
|
||||||
|
|
||||||
expect(parse.type).toEqual("text");
|
expect(parse.type).toEqual("text");
|
||||||
expect(parse.value).toBeDefined();
|
expect(parse.body).toBeDefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should produce textords instead of mathords", function() {
|
it("should produce textords instead of mathords", function() {
|
||||||
const parse = getParsed(textExpression)[0];
|
const parse = getParsed(textExpression)[0];
|
||||||
const group = parse.value.body;
|
const group = parse.body;
|
||||||
|
|
||||||
expect(group[0].type).toEqual("textord");
|
expect(group[0].type).toEqual("textord");
|
||||||
});
|
});
|
||||||
@@ -694,7 +694,7 @@ describe("A text parser", function() {
|
|||||||
|
|
||||||
it("should contract spaces", function() {
|
it("should contract spaces", function() {
|
||||||
const parse = getParsed(spaceTextExpression)[0];
|
const parse = getParsed(spaceTextExpression)[0];
|
||||||
const group = parse.value.body;
|
const group = parse.body;
|
||||||
|
|
||||||
expect(group[0].type).toEqual("spacing");
|
expect(group[0].type).toEqual("spacing");
|
||||||
expect(group[1].type).toEqual("textord");
|
expect(group[1].type).toEqual("textord");
|
||||||
@@ -709,10 +709,8 @@ describe("A text parser", function() {
|
|||||||
it("should ignore a space before the text group", function() {
|
it("should ignore a space before the text group", function() {
|
||||||
const parse = getParsed(leadingSpaceTextExpression)[0];
|
const parse = getParsed(leadingSpaceTextExpression)[0];
|
||||||
// [m, o, o]
|
// [m, o, o]
|
||||||
expect(parse.value.body).toHaveLength(3);
|
expect(parse.body).toHaveLength(3);
|
||||||
expect(
|
expect(parse.body.map(n => n.value).join("")).toBe("moo");
|
||||||
parse.value.body.map(function(n) { return n.value; }).join("")
|
|
||||||
).toBe("moo");
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should parse math within text group", function() {
|
it("should parse math within text group", function() {
|
||||||
@@ -860,14 +858,14 @@ describe("A tie parser", function() {
|
|||||||
|
|
||||||
it("should produce spacing in text mode", function() {
|
it("should produce spacing in text mode", function() {
|
||||||
const text = getParsed(textTie)[0];
|
const text = getParsed(textTie)[0];
|
||||||
const parse = text.value.body;
|
const parse = text.body;
|
||||||
|
|
||||||
expect(parse[1].type).toEqual("spacing");
|
expect(parse[1].type).toEqual("spacing");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not contract with spaces in text mode", function() {
|
it("should not contract with spaces in text mode", function() {
|
||||||
const text = getParsed(textTie)[0];
|
const text = getParsed(textTie)[0];
|
||||||
const parse = text.value.body;
|
const parse = text.body;
|
||||||
|
|
||||||
expect(parse[2].type).toEqual("spacing");
|
expect(parse[2].type).toEqual("spacing");
|
||||||
});
|
});
|
||||||
@@ -1241,7 +1239,7 @@ describe("A begin/end parser", function() {
|
|||||||
|
|
||||||
it("should eat a final newline", function() {
|
it("should eat a final newline", function() {
|
||||||
const m3 = getParsed`\begin{matrix}a&b\\ c&d \\ \end{matrix}`[0];
|
const m3 = getParsed`\begin{matrix}a&b\\ c&d \\ \end{matrix}`[0];
|
||||||
expect(m3.value.body).toHaveLength(2);
|
expect(m3.body).toHaveLength(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should grab \\arraystretch", function() {
|
it("should grab \\arraystretch", function() {
|
||||||
@@ -1440,10 +1438,10 @@ describe("A style change parser", function() {
|
|||||||
|
|
||||||
it("should produce the correct style", function() {
|
it("should produce the correct style", function() {
|
||||||
const displayParse = getParsed`\displaystyle x`[0];
|
const displayParse = getParsed`\displaystyle x`[0];
|
||||||
expect(displayParse.value.style).toEqual("display");
|
expect(displayParse.style).toEqual("display");
|
||||||
|
|
||||||
const scriptscriptParse = getParsed`\scriptscriptstyle x`[0];
|
const scriptscriptParse = getParsed`\scriptscriptstyle x`[0];
|
||||||
expect(scriptscriptParse.value.style).toEqual("scriptscript");
|
expect(scriptscriptParse.style).toEqual("scriptscript");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should only change the style within its group", function() {
|
it("should only change the style within its group", function() {
|
||||||
@@ -1454,7 +1452,7 @@ describe("A style change parser", function() {
|
|||||||
|
|
||||||
expect(displayNode.type).toEqual("styling");
|
expect(displayNode.type).toEqual("styling");
|
||||||
|
|
||||||
const displayBody = displayNode.value.value;
|
const displayBody = displayNode.body;
|
||||||
|
|
||||||
expect(displayBody).toHaveLength(2);
|
expect(displayBody).toHaveLength(2);
|
||||||
expect(displayBody[0].value).toEqual("e");
|
expect(displayBody[0].value).toEqual("e");
|
||||||
@@ -2407,7 +2405,7 @@ describe("An array environment", function() {
|
|||||||
it("should accept a single alignment character", function() {
|
it("should accept a single alignment character", function() {
|
||||||
const parse = getParsed`\begin{array}r1\\20\end{array}`;
|
const parse = getParsed`\begin{array}r1\\20\end{array}`;
|
||||||
expect(parse[0].type).toBe("array");
|
expect(parse[0].type).toBe("array");
|
||||||
expect(parse[0].value.cols).toEqual([
|
expect(parse[0].cols).toEqual([
|
||||||
{type: "align", align: "r"},
|
{type: "align", align: "r"},
|
||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
@@ -2415,7 +2413,7 @@ describe("An array environment", function() {
|
|||||||
it("should accept vertical separators", function() {
|
it("should accept vertical separators", function() {
|
||||||
const parse = getParsed`\begin{array}{|l||c:r::}\end{array}`;
|
const parse = getParsed`\begin{array}{|l||c:r::}\end{array}`;
|
||||||
expect(parse[0].type).toBe("array");
|
expect(parse[0].type).toBe("array");
|
||||||
expect(parse[0].value.cols).toEqual([
|
expect(parse[0].cols).toEqual([
|
||||||
{type: "separator", separator: "|"},
|
{type: "separator", separator: "|"},
|
||||||
{type: "align", align: "l"},
|
{type: "align", align: "l"},
|
||||||
{type: "separator", separator: "|"},
|
{type: "separator", separator: "|"},
|
||||||
@@ -2455,7 +2453,7 @@ describe("An aligned environment", function() {
|
|||||||
|
|
||||||
it("should not eat the last row when its first cell is empty", function() {
|
it("should not eat the last row when its first cell is empty", function() {
|
||||||
const ae = getParsed`\begin{aligned}&E_1 & (1)\\&E_2 & (2)\\&E_3 & (3)\end{aligned}`[0];
|
const ae = getParsed`\begin{aligned}&E_1 & (1)\\&E_2 & (2)\\&E_3 & (3)\end{aligned}`[0];
|
||||||
expect(ae.value.body).toHaveLength(3);
|
expect(ae.body).toHaveLength(3);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user