mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-19 09:38:40 +00:00
Flatten a bunch of non-pervasive ParseNode types (part 2) (#1552)
* Flatten "operatorname" ParseNode. * Flatten "overline" ParseNode. * Flatten "raisebox" ParseNode. * Flatten "rule" ParseNode. * Flatten "sizing" ParseNode. * Flatten "smash" ParseNode. * Flatten "sqrt" ParseNode. * Flatten "underline" ParseNode. * Flatten "enclose" ParseNode. * Flatten "environment" ParseNode. * Flatten "genfrac" ParseNode. * Flatten "htmlmathml" ParseNode. * Flatten "infix" ParseNode. * Flatten "kern" ParseNode. * Flatten "lap" ParseNode. * Flatten "color" ParseNode.
This commit is contained in:
@@ -223,10 +223,10 @@ export default class Parser {
|
||||
if (overIndex !== -1) {
|
||||
throw new ParseError(
|
||||
"only one infix operator per group",
|
||||
node.value.token);
|
||||
node.token);
|
||||
}
|
||||
overIndex = i;
|
||||
funcName = node.value.replaceWith;
|
||||
funcName = node.replaceWith;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,12 +327,9 @@ export default class Parser {
|
||||
|
||||
const colorNode = {
|
||||
type: "color",
|
||||
value: {
|
||||
type: "color",
|
||||
color: this.settings.errorColor,
|
||||
value: [textNode],
|
||||
},
|
||||
mode: this.mode,
|
||||
color: this.settings.errorColor,
|
||||
body: [textNode],
|
||||
};
|
||||
|
||||
this.consume();
|
||||
@@ -460,10 +457,10 @@ export default class Parser {
|
||||
const begin =
|
||||
assertNodeType(this.parseGivenFunction(start), "environment");
|
||||
|
||||
const envName = begin.value.name;
|
||||
const envName = begin.name;
|
||||
if (!environments.hasOwnProperty(envName)) {
|
||||
throw new ParseError(
|
||||
"No such environment: " + envName, begin.value.nameGroup);
|
||||
"No such environment: " + envName, begin.nameGroup);
|
||||
}
|
||||
// Build the environment object. Arguments and other information will
|
||||
// be made available to the begin and end methods using properties.
|
||||
@@ -483,10 +480,9 @@ export default class Parser {
|
||||
throw new ParseError("failed to parse function after \\end");
|
||||
}
|
||||
end = assertNodeType(end, "environment");
|
||||
if (end.value.name !== envName) {
|
||||
if (end.name !== envName) {
|
||||
throw new ParseError(
|
||||
"Mismatch: \\begin{" + envName + "} matched " +
|
||||
"by \\end{" + end.value.name + "}",
|
||||
`Mismatch: \\begin{${envName}} matched by \\end{${end.name}}`,
|
||||
endNameToken);
|
||||
}
|
||||
return result;
|
||||
|
@@ -169,7 +169,7 @@ export const buildExpression = function(
|
||||
if (!node) {
|
||||
// No match.
|
||||
} else if (node.type === "sizing") {
|
||||
glueOptions = options.havingSize(node.value.size);
|
||||
glueOptions = options.havingSize(node.size);
|
||||
} else if (node.type === "styling") {
|
||||
glueOptions = options.havingStyle(
|
||||
styleMap[node.value.style]);
|
||||
|
@@ -9,8 +9,8 @@ import * as mml from "../buildMathML";
|
||||
|
||||
const htmlBuilder = (group, options) => {
|
||||
const elements = html.buildExpression(
|
||||
group.value.value,
|
||||
options.withColor(group.value.color),
|
||||
group.body,
|
||||
options.withColor(group.color),
|
||||
false
|
||||
);
|
||||
|
||||
@@ -22,11 +22,11 @@ const htmlBuilder = (group, options) => {
|
||||
};
|
||||
|
||||
const mathmlBuilder = (group, options) => {
|
||||
const inner = mml.buildExpression(group.value.value, options);
|
||||
const inner = mml.buildExpression(group.body, options);
|
||||
|
||||
const node = new mathMLTree.MathNode("mstyle", inner);
|
||||
|
||||
node.setAttribute("mathcolor", group.value.color);
|
||||
node.setAttribute("mathcolor", group.color);
|
||||
|
||||
return node;
|
||||
};
|
||||
@@ -46,11 +46,8 @@ defineFunction({
|
||||
return {
|
||||
type: "color",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "color",
|
||||
color: color.value,
|
||||
value: ordargument(body),
|
||||
},
|
||||
color: color.value,
|
||||
body: ordargument(body),
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
@@ -85,11 +82,8 @@ defineFunction({
|
||||
return {
|
||||
type: "color",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "color",
|
||||
color: "katex-" + funcName.slice(1),
|
||||
value: ordargument(body),
|
||||
},
|
||||
color: "katex-" + funcName.slice(1),
|
||||
body: ordargument(body),
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
@@ -114,11 +108,8 @@ defineFunction({
|
||||
return {
|
||||
type: "color",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "color",
|
||||
color: color.value,
|
||||
value: body,
|
||||
},
|
||||
color: color.value,
|
||||
body,
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
|
@@ -12,9 +12,9 @@ import * as mml from "../buildMathML";
|
||||
|
||||
const htmlBuilder = (group, options) => {
|
||||
// \cancel, \bcancel, \xcancel, \sout, \fbox, \colorbox, \fcolorbox
|
||||
const inner = html.buildGroup(group.value.body, options);
|
||||
const inner = html.buildGroup(group.body, options);
|
||||
|
||||
const label = group.value.label.substr(1);
|
||||
const label = group.label.substr(1);
|
||||
const scale = options.sizeMultiplier;
|
||||
let img;
|
||||
let imgShift = 0;
|
||||
@@ -24,7 +24,7 @@ const htmlBuilder = (group, options) => {
|
||||
// We don't know the width of a group, so as a proxy, we test if
|
||||
// the subject is a single character. This captures most of the
|
||||
// subjects that should get the "tall" treatment.
|
||||
const isSingleChar = utils.isCharacterBox(group.value.body);
|
||||
const isSingleChar = utils.isCharacterBox(group.body);
|
||||
|
||||
if (label === "sout") {
|
||||
img = buildCommon.makeSpan(["stretchy", "sout"]);
|
||||
@@ -54,16 +54,16 @@ const htmlBuilder = (group, options) => {
|
||||
img = stretchy.encloseSpan(inner, label, vertPad, options);
|
||||
imgShift = inner.depth + vertPad;
|
||||
|
||||
if (group.value.backgroundColor) {
|
||||
img.style.backgroundColor = group.value.backgroundColor.value;
|
||||
if (group.value.borderColor) {
|
||||
img.style.borderColor = group.value.borderColor.value;
|
||||
if (group.backgroundColor) {
|
||||
img.style.backgroundColor = group.backgroundColor.value;
|
||||
if (group.borderColor) {
|
||||
img.style.borderColor = group.borderColor.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let vlist;
|
||||
if (group.value.backgroundColor) {
|
||||
if (group.backgroundColor) {
|
||||
vlist = buildCommon.makeVList({
|
||||
positionType: "individualShift",
|
||||
children: [
|
||||
@@ -109,8 +109,8 @@ const htmlBuilder = (group, options) => {
|
||||
|
||||
const mathmlBuilder = (group, options) => {
|
||||
const node = new mathMLTree.MathNode(
|
||||
"menclose", [mml.buildGroup(group.value.body, options)]);
|
||||
switch (group.value.label) {
|
||||
"menclose", [mml.buildGroup(group.body, options)]);
|
||||
switch (group.label) {
|
||||
case "\\cancel":
|
||||
node.setAttribute("notation", "updiagonalstrike");
|
||||
break;
|
||||
@@ -131,8 +131,8 @@ const mathmlBuilder = (group, options) => {
|
||||
node.setAttribute("notation", "updiagonalstrike downdiagonalstrike");
|
||||
break;
|
||||
}
|
||||
if (group.value.backgroundColor) {
|
||||
node.setAttribute("mathbackground", group.value.backgroundColor.value);
|
||||
if (group.backgroundColor) {
|
||||
node.setAttribute("mathbackground", group.backgroundColor.value);
|
||||
}
|
||||
return node;
|
||||
};
|
||||
@@ -152,12 +152,9 @@ defineFunction({
|
||||
return {
|
||||
type: "enclose",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "enclose",
|
||||
label: funcName,
|
||||
backgroundColor: color,
|
||||
body: body,
|
||||
},
|
||||
label: funcName,
|
||||
backgroundColor: color,
|
||||
body,
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
@@ -180,13 +177,10 @@ defineFunction({
|
||||
return {
|
||||
type: "enclose",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "enclose",
|
||||
label: funcName,
|
||||
backgroundColor: backgroundColor,
|
||||
borderColor: borderColor,
|
||||
body: body,
|
||||
},
|
||||
label: funcName,
|
||||
backgroundColor: backgroundColor,
|
||||
borderColor: borderColor,
|
||||
body,
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
@@ -205,11 +199,8 @@ defineFunction({
|
||||
return {
|
||||
type: "enclose",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "enclose",
|
||||
label: "\\fbox",
|
||||
body: args[0],
|
||||
},
|
||||
label: "\\fbox",
|
||||
body: args[0],
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -225,11 +216,8 @@ defineFunction({
|
||||
return {
|
||||
type: "enclose",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "enclose",
|
||||
label: funcName,
|
||||
body: body,
|
||||
},
|
||||
label: funcName,
|
||||
body,
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
|
@@ -24,11 +24,8 @@ defineFunction({
|
||||
return {
|
||||
type: "environment",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "environment",
|
||||
name: name,
|
||||
nameGroup: nameGroup,
|
||||
},
|
||||
name,
|
||||
nameGroup,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
@@ -15,15 +15,15 @@ const htmlBuilder = (group, options) => {
|
||||
// Figure out what style this fraction should be in based on the
|
||||
// function used
|
||||
let style = options.style;
|
||||
if (group.value.size === "display") {
|
||||
if (group.size === "display") {
|
||||
style = Style.DISPLAY;
|
||||
} else if (group.value.size === "text" &&
|
||||
} else if (group.size === "text" &&
|
||||
style.size === Style.DISPLAY.size) {
|
||||
// We're in a \tfrac but incoming style is displaystyle, so:
|
||||
style = Style.TEXT;
|
||||
} else if (group.value.size === "script") {
|
||||
} else if (group.size === "script") {
|
||||
style = Style.SCRIPT;
|
||||
} else if (group.value.size === "scriptscript") {
|
||||
} else if (group.size === "scriptscript") {
|
||||
style = Style.SCRIPTSCRIPT;
|
||||
}
|
||||
|
||||
@@ -32,9 +32,9 @@ const htmlBuilder = (group, options) => {
|
||||
let newOptions;
|
||||
|
||||
newOptions = options.havingStyle(nstyle);
|
||||
const numerm = html.buildGroup(group.value.numer, newOptions, options);
|
||||
const numerm = html.buildGroup(group.numer, newOptions, options);
|
||||
|
||||
if (group.value.continued) {
|
||||
if (group.continued) {
|
||||
// \cfrac inserts a \strut into the numerator.
|
||||
// Get \strut dimensions from TeXbook page 353.
|
||||
const hStrut = 8.5 / options.fontMetrics().ptPerEm;
|
||||
@@ -44,14 +44,14 @@ const htmlBuilder = (group, options) => {
|
||||
}
|
||||
|
||||
newOptions = options.havingStyle(dstyle);
|
||||
const denomm = html.buildGroup(group.value.denom, newOptions, options);
|
||||
const denomm = html.buildGroup(group.denom, newOptions, options);
|
||||
|
||||
let rule;
|
||||
let ruleWidth;
|
||||
let ruleSpacing;
|
||||
if (group.value.hasBarLine) {
|
||||
if (group.value.barSize) {
|
||||
ruleWidth = calculateSize(group.value.barSize, options);
|
||||
if (group.hasBarLine) {
|
||||
if (group.barSize) {
|
||||
ruleWidth = calculateSize(group.barSize, options);
|
||||
rule = buildCommon.makeLineSpan("frac-line", options, ruleWidth);
|
||||
} else {
|
||||
rule = buildCommon.makeLineSpan("frac-line", options);
|
||||
@@ -150,21 +150,21 @@ const htmlBuilder = (group, options) => {
|
||||
|
||||
let leftDelim;
|
||||
let rightDelim;
|
||||
if (group.value.leftDelim == null) {
|
||||
if (group.leftDelim == null) {
|
||||
leftDelim = html.makeNullDelimiter(options, ["mopen"]);
|
||||
} else {
|
||||
leftDelim = delimiter.customSizedDelim(
|
||||
group.value.leftDelim, delimSize, true,
|
||||
group.leftDelim, delimSize, true,
|
||||
options.havingStyle(style), group.mode, ["mopen"]);
|
||||
}
|
||||
|
||||
if (group.value.continued) {
|
||||
if (group.continued) {
|
||||
rightDelim = buildCommon.makeSpan([]); // zero width for \cfrac
|
||||
} else if (group.value.rightDelim == null) {
|
||||
} else if (group.rightDelim == null) {
|
||||
rightDelim = html.makeNullDelimiter(options, ["mclose"]);
|
||||
} else {
|
||||
rightDelim = delimiter.customSizedDelim(
|
||||
group.value.rightDelim, delimSize, true,
|
||||
group.rightDelim, delimSize, true,
|
||||
options.havingStyle(style), group.mode, ["mclose"]);
|
||||
}
|
||||
|
||||
@@ -178,23 +178,23 @@ const mathmlBuilder = (group, options) => {
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mfrac",
|
||||
[
|
||||
mml.buildGroup(group.value.numer, options),
|
||||
mml.buildGroup(group.value.denom, options),
|
||||
mml.buildGroup(group.numer, options),
|
||||
mml.buildGroup(group.denom, options),
|
||||
]);
|
||||
|
||||
if (!group.value.hasBarLine) {
|
||||
if (!group.hasBarLine) {
|
||||
node.setAttribute("linethickness", "0px");
|
||||
} else if (group.value.barSize) {
|
||||
const ruleWidth = calculateSize(group.value.barSize, options);
|
||||
} else if (group.barSize) {
|
||||
const ruleWidth = calculateSize(group.barSize, options);
|
||||
node.setAttribute("linethickness", ruleWidth + "em");
|
||||
}
|
||||
|
||||
if (group.value.leftDelim != null || group.value.rightDelim != null) {
|
||||
if (group.leftDelim != null || group.rightDelim != null) {
|
||||
const withDelims = [];
|
||||
|
||||
if (group.value.leftDelim != null) {
|
||||
if (group.leftDelim != null) {
|
||||
const leftOp = new mathMLTree.MathNode(
|
||||
"mo", [new mathMLTree.TextNode(group.value.leftDelim)]);
|
||||
"mo", [new mathMLTree.TextNode(group.leftDelim)]);
|
||||
|
||||
leftOp.setAttribute("fence", "true");
|
||||
|
||||
@@ -203,9 +203,9 @@ const mathmlBuilder = (group, options) => {
|
||||
|
||||
withDelims.push(node);
|
||||
|
||||
if (group.value.rightDelim != null) {
|
||||
if (group.rightDelim != null) {
|
||||
const rightOp = new mathMLTree.MathNode(
|
||||
"mo", [new mathMLTree.TextNode(group.value.rightDelim)]);
|
||||
"mo", [new mathMLTree.TextNode(group.rightDelim)]);
|
||||
|
||||
rightOp.setAttribute("fence", "true");
|
||||
|
||||
@@ -284,17 +284,14 @@ defineFunction({
|
||||
return {
|
||||
type: "genfrac",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "genfrac",
|
||||
continued: funcName === "\\cfrac",
|
||||
numer: numer,
|
||||
denom: denom,
|
||||
hasBarLine: hasBarLine,
|
||||
leftDelim: leftDelim,
|
||||
rightDelim: rightDelim,
|
||||
size: size,
|
||||
barSize: null,
|
||||
},
|
||||
continued: funcName === "\\cfrac",
|
||||
numer,
|
||||
denom,
|
||||
hasBarLine,
|
||||
leftDelim,
|
||||
rightDelim,
|
||||
size,
|
||||
barSize: null,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -335,11 +332,8 @@ defineFunction({
|
||||
return {
|
||||
type: "infix",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "infix",
|
||||
replaceWith: replaceWith,
|
||||
token: token,
|
||||
},
|
||||
replaceWith,
|
||||
token,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -413,17 +407,14 @@ defineFunction({
|
||||
return {
|
||||
type: "genfrac",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "genfrac",
|
||||
numer: numer,
|
||||
denom: denom,
|
||||
continued: false,
|
||||
hasBarLine: hasBarLine,
|
||||
barSize: barSize,
|
||||
leftDelim: leftDelim,
|
||||
rightDelim: rightDelim,
|
||||
size: size,
|
||||
},
|
||||
numer,
|
||||
denom,
|
||||
continued: false,
|
||||
hasBarLine,
|
||||
barSize,
|
||||
leftDelim,
|
||||
rightDelim,
|
||||
size,
|
||||
};
|
||||
},
|
||||
|
||||
@@ -445,12 +436,9 @@ defineFunction({
|
||||
return {
|
||||
type: "infix",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "infix",
|
||||
replaceWith: "\\\\abovefrac",
|
||||
sizeNode: sizeNode,
|
||||
token: token,
|
||||
},
|
||||
replaceWith: "\\\\abovefrac",
|
||||
sizeNode,
|
||||
token,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -465,7 +453,7 @@ defineFunction({
|
||||
handler: ({parser, funcName}, args) => {
|
||||
const numer = args[0];
|
||||
const infixNode = assertNodeType(args[1], "infix");
|
||||
const sizeNode = assertNodeType(infixNode.value.sizeNode, "size");
|
||||
const sizeNode = assertNodeType(infixNode.sizeNode, "size");
|
||||
const denom = args[2];
|
||||
|
||||
const barSize = sizeNode.value.value;
|
||||
@@ -473,17 +461,14 @@ defineFunction({
|
||||
return {
|
||||
type: "genfrac",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "genfrac",
|
||||
numer: numer,
|
||||
denom: denom,
|
||||
continued: false,
|
||||
hasBarLine: hasBarLine,
|
||||
barSize: barSize,
|
||||
leftDelim: null,
|
||||
rightDelim: null,
|
||||
size: "auto",
|
||||
},
|
||||
numer,
|
||||
denom,
|
||||
continued: false,
|
||||
hasBarLine,
|
||||
barSize,
|
||||
leftDelim: null,
|
||||
rightDelim: null,
|
||||
size: "auto",
|
||||
};
|
||||
},
|
||||
|
||||
|
@@ -16,22 +16,19 @@ defineFunction({
|
||||
return {
|
||||
type: "htmlmathml",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "htmlmathml",
|
||||
html: ordargument(args[0]),
|
||||
mathml: ordargument(args[1]),
|
||||
},
|
||||
html: ordargument(args[0]),
|
||||
mathml: ordargument(args[1]),
|
||||
};
|
||||
},
|
||||
htmlBuilder: (group, options) => {
|
||||
const elements = html.buildExpression(
|
||||
group.value.html,
|
||||
group.html,
|
||||
options,
|
||||
false
|
||||
);
|
||||
return new buildCommon.makeFragment(elements);
|
||||
},
|
||||
mathmlBuilder: (group, options) => {
|
||||
return mml.buildExpressionRow(group.value.mathml, options);
|
||||
return mml.buildExpressionRow(group.mathml, options);
|
||||
},
|
||||
});
|
||||
|
@@ -42,17 +42,14 @@ defineFunction({
|
||||
return {
|
||||
type: "kern",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "kern",
|
||||
dimension: size.value.value,
|
||||
},
|
||||
dimension: size.value.value,
|
||||
};
|
||||
},
|
||||
htmlBuilder: (group, options) => {
|
||||
return buildCommon.makeGlue(group.value.dimension, options);
|
||||
return buildCommon.makeGlue(group.dimension, options);
|
||||
},
|
||||
mathmlBuilder: (group, options) => {
|
||||
const dimension = calculateSize(group.value.dimension, options);
|
||||
const dimension = calculateSize(group.dimension, options);
|
||||
return new mathMLTree.SpaceNode(dimension);
|
||||
},
|
||||
});
|
||||
|
@@ -19,29 +19,26 @@ defineFunction({
|
||||
return {
|
||||
type: "lap",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "lap",
|
||||
alignment: funcName.slice(5),
|
||||
body: body,
|
||||
},
|
||||
alignment: funcName.slice(5),
|
||||
body,
|
||||
};
|
||||
},
|
||||
htmlBuilder: (group, options) => {
|
||||
// mathllap, mathrlap, mathclap
|
||||
let inner;
|
||||
if (group.value.alignment === "clap") {
|
||||
if (group.alignment === "clap") {
|
||||
// ref: https://www.math.lsu.edu/~aperlis/publications/mathclap/
|
||||
inner = buildCommon.makeSpan(
|
||||
[], [html.buildGroup(group.value.body, options)]);
|
||||
[], [html.buildGroup(group.body, options)]);
|
||||
// wrap, since CSS will center a .clap > .inner > span
|
||||
inner = buildCommon.makeSpan(["inner"], [inner], options);
|
||||
} else {
|
||||
inner = buildCommon.makeSpan(
|
||||
["inner"], [html.buildGroup(group.value.body, options)]);
|
||||
["inner"], [html.buildGroup(group.body, options)]);
|
||||
}
|
||||
const fix = buildCommon.makeSpan(["fix"], []);
|
||||
let node = buildCommon.makeSpan(
|
||||
[group.value.alignment], [inner, fix], options);
|
||||
[group.alignment], [inner, fix], options);
|
||||
|
||||
// At this point, we have correctly set horizontal alignment of the
|
||||
// two items involved in the lap.
|
||||
@@ -64,10 +61,10 @@ defineFunction({
|
||||
mathmlBuilder: (group, options) => {
|
||||
// mathllap, mathrlap, mathclap
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mpadded", [mml.buildGroup(group.value.body, options)]);
|
||||
"mpadded", [mml.buildGroup(group.body, options)]);
|
||||
|
||||
if (group.value.alignment !== "rlap") {
|
||||
const offset = (group.value.alignment === "llap" ? "-1" : "-0.5");
|
||||
if (group.alignment !== "rlap") {
|
||||
const offset = (group.alignment === "llap" ? "-1" : "-0.5");
|
||||
node.setAttribute("lspace", offset + "width");
|
||||
}
|
||||
node.setAttribute("width", "0px");
|
||||
|
@@ -20,16 +20,13 @@ defineFunction({
|
||||
return {
|
||||
type: "operatorname",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "operatorname",
|
||||
value: ordargument(body),
|
||||
},
|
||||
body: ordargument(body),
|
||||
};
|
||||
},
|
||||
|
||||
htmlBuilder: (group, options) => {
|
||||
if (group.value.value.length > 0) {
|
||||
const groupValue = group.value.value.map(child => {
|
||||
if (group.body.length > 0) {
|
||||
const body = group.body.map(child => {
|
||||
// $FlowFixMe: Check if the node has a string `value` property.
|
||||
const childValue = child.value;
|
||||
if (typeof childValue === "string") {
|
||||
@@ -45,7 +42,7 @@ defineFunction({
|
||||
|
||||
// Consolidate function names into symbol characters.
|
||||
const expression = html.buildExpression(
|
||||
groupValue, options.withFont("mathrm"), true);
|
||||
body, options.withFont("mathrm"), true);
|
||||
|
||||
for (let i = 0; i < expression.length; i++) {
|
||||
const child = expression[i];
|
||||
@@ -65,7 +62,7 @@ defineFunction({
|
||||
mathmlBuilder: (group, options) => {
|
||||
// The steps taken here are similar to the html version.
|
||||
let expression = mml.buildExpression(
|
||||
group.value.value, options.withFont("mathrm"));
|
||||
group.body, options.withFont("mathrm"));
|
||||
|
||||
// Is expression a string or has it something like a fraction?
|
||||
let isAllString = true; // default
|
||||
|
@@ -17,17 +17,14 @@ defineFunction({
|
||||
return {
|
||||
type: "overline",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "overline",
|
||||
body: body,
|
||||
},
|
||||
body,
|
||||
};
|
||||
},
|
||||
htmlBuilder(group, options) {
|
||||
// Overlines are handled in the TeXbook pg 443, Rule 9.
|
||||
|
||||
// Build the inner group in the cramped style.
|
||||
const innerGroup = html.buildGroup(group.value.body,
|
||||
const innerGroup = html.buildGroup(group.body,
|
||||
options.havingCrampedStyle());
|
||||
|
||||
// Create the line above the body
|
||||
@@ -53,7 +50,7 @@ defineFunction({
|
||||
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mover",
|
||||
[mml.buildGroup(group.value.body, options), operator]);
|
||||
[mml.buildGroup(group.body, options), operator]);
|
||||
node.setAttribute("accent", "true");
|
||||
|
||||
return node;
|
||||
|
@@ -23,12 +23,8 @@ defineFunction({
|
||||
return {
|
||||
type: "raisebox",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "raisebox",
|
||||
dy: amount,
|
||||
body: body,
|
||||
value: ordargument(body),
|
||||
},
|
||||
dy: amount,
|
||||
body,
|
||||
};
|
||||
},
|
||||
htmlBuilder(group, options) {
|
||||
@@ -37,21 +33,18 @@ defineFunction({
|
||||
mode: group.mode,
|
||||
value: {
|
||||
type: "text",
|
||||
body: group.value.value,
|
||||
body: ordargument(group.body),
|
||||
font: "mathrm", // simulate \textrm
|
||||
},
|
||||
};
|
||||
const sizedText = {
|
||||
type: "sizing",
|
||||
mode: group.mode,
|
||||
value: {
|
||||
type: "sizing",
|
||||
value: [text],
|
||||
size: 6, // simulate \normalsize
|
||||
},
|
||||
body: [text],
|
||||
size: 6, // simulate \normalsize
|
||||
};
|
||||
const body = sizing.htmlBuilder(sizedText, options);
|
||||
const dy = calculateSize(group.value.dy.value.value, options);
|
||||
const dy = calculateSize(group.dy.value.value, options);
|
||||
return buildCommon.makeVList({
|
||||
positionType: "shift",
|
||||
positionData: -dy,
|
||||
@@ -60,9 +53,8 @@ defineFunction({
|
||||
},
|
||||
mathmlBuilder(group, options) {
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mpadded", [mml.buildGroup(group.value.body, options)]);
|
||||
const dy =
|
||||
group.value.dy.value.value.number + group.value.dy.value.value.unit;
|
||||
"mpadded", [mml.buildGroup(group.body, options)]);
|
||||
const dy = group.dy.value.value.number + group.dy.value.value.unit;
|
||||
node.setAttribute("voffset", dy);
|
||||
return node;
|
||||
},
|
||||
|
@@ -20,12 +20,9 @@ defineFunction({
|
||||
return {
|
||||
type: "rule",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "rule",
|
||||
shift: shift && assertNodeType(shift, "size").value.value,
|
||||
width: width.value.value,
|
||||
height: height.value.value,
|
||||
},
|
||||
shift: shift && assertNodeType(shift, "size").value.value,
|
||||
width: width.value.value,
|
||||
height: height.value.value,
|
||||
};
|
||||
},
|
||||
htmlBuilder(group, options) {
|
||||
@@ -34,12 +31,12 @@ defineFunction({
|
||||
|
||||
// Calculate the shift, width, and height of the rule, and account for units
|
||||
let shift = 0;
|
||||
if (group.value.shift) {
|
||||
shift = calculateSize(group.value.shift, options);
|
||||
if (group.shift) {
|
||||
shift = calculateSize(group.shift, options);
|
||||
}
|
||||
|
||||
const width = calculateSize(group.value.width, options);
|
||||
const height = calculateSize(group.value.height, options);
|
||||
const width = calculateSize(group.width, options);
|
||||
const height = calculateSize(group.height, options);
|
||||
|
||||
// Style the rule to the right size
|
||||
rule.style.borderRightWidth = width + "em";
|
||||
|
@@ -8,9 +8,15 @@ import * as html from "../buildHTML";
|
||||
import * as mml from "../buildMathML";
|
||||
|
||||
import type Options from "../Options";
|
||||
import type {AnyParseNode} from "../parseNode";
|
||||
import type {HtmlBuilder} from "../defineFunction";
|
||||
import type {documentFragment as HtmlDocumentFragment} from "../domTree";
|
||||
|
||||
export function sizingGroup(value: *, options: Options, baseOptions: Options) {
|
||||
export function sizingGroup(
|
||||
value: AnyParseNode[],
|
||||
options: Options,
|
||||
baseOptions: Options,
|
||||
): HtmlDocumentFragment {
|
||||
const inner = html.buildExpression(value, options, false);
|
||||
const multiplier = options.sizeMultiplier / baseOptions.sizeMultiplier;
|
||||
|
||||
@@ -44,8 +50,8 @@ export const htmlBuilder: HtmlBuilder<"sizing"> = (group, options) => {
|
||||
// Handle sizing operators like \Huge. Real TeX doesn't actually allow
|
||||
// these functions inside of math expressions, so we do some special
|
||||
// handling.
|
||||
const newOptions = options.havingSize(group.value.size);
|
||||
return sizingGroup(group.value.value, newOptions, options);
|
||||
const newOptions = options.havingSize(group.size);
|
||||
return sizingGroup(group.body, newOptions, options);
|
||||
};
|
||||
|
||||
defineFunction({
|
||||
@@ -62,18 +68,15 @@ defineFunction({
|
||||
return {
|
||||
type: "sizing",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "sizing",
|
||||
// Figure out what size to use based on the list of functions above
|
||||
size: utils.indexOf(sizeFuncs, funcName) + 1,
|
||||
value: body,
|
||||
},
|
||||
// Figure out what size to use based on the list of functions above
|
||||
size: utils.indexOf(sizeFuncs, funcName) + 1,
|
||||
body,
|
||||
};
|
||||
},
|
||||
htmlBuilder,
|
||||
mathmlBuilder: (group, options) => {
|
||||
const newOptions = options.havingSize(group.value.size);
|
||||
const inner = mml.buildExpression(group.value.value, newOptions);
|
||||
const newOptions = options.havingSize(group.size);
|
||||
const inner = mml.buildExpression(group.body, newOptions);
|
||||
|
||||
const node = new mathMLTree.MathNode("mstyle", inner);
|
||||
|
||||
|
@@ -48,23 +48,20 @@ defineFunction({
|
||||
return {
|
||||
type: "smash",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "smash",
|
||||
body: body,
|
||||
smashHeight: smashHeight,
|
||||
smashDepth: smashDepth,
|
||||
},
|
||||
body,
|
||||
smashHeight,
|
||||
smashDepth,
|
||||
};
|
||||
},
|
||||
htmlBuilder: (group, options) => {
|
||||
const node = buildCommon.makeSpan(
|
||||
["mord"], [html.buildGroup(group.value.body, options)]);
|
||||
["mord"], [html.buildGroup(group.body, options)]);
|
||||
|
||||
if (!group.value.smashHeight && !group.value.smashDepth) {
|
||||
if (!group.smashHeight && !group.smashDepth) {
|
||||
return node;
|
||||
}
|
||||
|
||||
if (group.value.smashHeight) {
|
||||
if (group.smashHeight) {
|
||||
node.height = 0;
|
||||
// In order to influence makeVList, we have to reset the children.
|
||||
if (node.children) {
|
||||
@@ -74,7 +71,7 @@ defineFunction({
|
||||
}
|
||||
}
|
||||
|
||||
if (group.value.smashDepth) {
|
||||
if (group.smashDepth) {
|
||||
node.depth = 0;
|
||||
if (node.children) {
|
||||
for (let i = 0; i < node.children.length; i++) {
|
||||
@@ -95,13 +92,13 @@ defineFunction({
|
||||
},
|
||||
mathmlBuilder: (group, options) => {
|
||||
const node = new mathMLTree.MathNode(
|
||||
"mpadded", [mml.buildGroup(group.value.body, options)]);
|
||||
"mpadded", [mml.buildGroup(group.body, options)]);
|
||||
|
||||
if (group.value.smashHeight) {
|
||||
if (group.smashHeight) {
|
||||
node.setAttribute("height", "0px");
|
||||
}
|
||||
|
||||
if (group.value.smashDepth) {
|
||||
if (group.smashDepth) {
|
||||
node.setAttribute("depth", "0px");
|
||||
}
|
||||
|
||||
|
@@ -22,11 +22,8 @@ defineFunction({
|
||||
return {
|
||||
type: "sqrt",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "sqrt",
|
||||
body: body,
|
||||
index: index,
|
||||
},
|
||||
body,
|
||||
index,
|
||||
};
|
||||
},
|
||||
htmlBuilder(group, options) {
|
||||
@@ -34,7 +31,7 @@ defineFunction({
|
||||
|
||||
// First, we do the same steps as in overline to build the inner group
|
||||
// and line
|
||||
let inner = html.buildGroup(group.value.body, options.havingCrampedStyle());
|
||||
let inner = html.buildGroup(group.body, options.havingCrampedStyle());
|
||||
if (inner.height === 0) {
|
||||
// Render a small surd.
|
||||
inner.height = options.fontMetrics().xHeight;
|
||||
@@ -89,14 +86,14 @@ defineFunction({
|
||||
],
|
||||
}, options);
|
||||
|
||||
if (!group.value.index) {
|
||||
if (!group.index) {
|
||||
return buildCommon.makeSpan(["mord", "sqrt"], [body], options);
|
||||
} else {
|
||||
// Handle the optional root index
|
||||
|
||||
// The index is always in scriptscript style
|
||||
const newOptions = options.havingStyle(Style.SCRIPTSCRIPT);
|
||||
const rootm = html.buildGroup(group.value.index, newOptions, options);
|
||||
const rootm = html.buildGroup(group.index, newOptions, options);
|
||||
|
||||
// The amount the index is shifted by. This is taken from the TeX
|
||||
// source, in the definition of `\r@@t`.
|
||||
@@ -117,7 +114,7 @@ defineFunction({
|
||||
}
|
||||
},
|
||||
mathmlBuilder(group, options) {
|
||||
const {body, index} = group.value;
|
||||
const {body, index} = group;
|
||||
return index ?
|
||||
new mathMLTree.MathNode(
|
||||
"mroot", [
|
||||
|
@@ -14,20 +14,16 @@ defineFunction({
|
||||
allowedInText: true,
|
||||
},
|
||||
handler({parser}, args) {
|
||||
const body = args[0];
|
||||
return {
|
||||
type: "underline",
|
||||
mode: parser.mode,
|
||||
value: {
|
||||
type: "underline",
|
||||
body: body,
|
||||
},
|
||||
body: args[0],
|
||||
};
|
||||
},
|
||||
htmlBuilder(group, options) {
|
||||
// Underlines are handled in the TeXbook pg 443, Rule 10.
|
||||
// Build the inner group.
|
||||
const innerGroup = html.buildGroup(group.value.body, options);
|
||||
const innerGroup = html.buildGroup(group.body, options);
|
||||
|
||||
// Create the line to go below the body
|
||||
const line = buildCommon.makeLineSpan("underline-line", options);
|
||||
@@ -53,7 +49,7 @@ defineFunction({
|
||||
|
||||
const node = new mathMLTree.MathNode(
|
||||
"munder",
|
||||
[mml.buildGroup(group.value.body, options), operator]);
|
||||
[mml.buildGroup(group.body, options), operator]);
|
||||
node.setAttribute("accentunder", "true");
|
||||
|
||||
return node;
|
||||
|
127
src/parseNode.js
127
src/parseNode.js
@@ -34,11 +34,8 @@ type ParseNodeTypes = {
|
||||
type: "color",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "color",
|
||||
color: string,
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
color: string,
|
||||
body: AnyParseNode[],
|
||||
|},
|
||||
"color-token": {|
|
||||
type: "color-token",
|
||||
@@ -216,23 +213,17 @@ type ParseNodeTypes = {
|
||||
type: "enclose",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "enclose",
|
||||
label: string,
|
||||
backgroundColor?: ParseNode<"color-token">,
|
||||
borderColor?: ParseNode<"color-token">,
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
label: string,
|
||||
backgroundColor?: ParseNode<"color-token">,
|
||||
borderColor?: ParseNode<"color-token">,
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
"environment": {|
|
||||
type: "environment",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "environment",
|
||||
name: string,
|
||||
nameGroup: AnyParseNode,
|
||||
|},
|
||||
name: string,
|
||||
nameGroup: AnyParseNode,
|
||||
|},
|
||||
"font": {|
|
||||
type: "font",
|
||||
@@ -245,17 +236,14 @@ type ParseNodeTypes = {
|
||||
type: "genfrac",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "genfrac",
|
||||
continued: boolean,
|
||||
numer: AnyParseNode,
|
||||
denom: AnyParseNode,
|
||||
hasBarLine: boolean,
|
||||
leftDelim: ?string,
|
||||
rightDelim: ?string,
|
||||
size: StyleStr | "auto",
|
||||
barSize: Measurement | null,
|
||||
|},
|
||||
continued: boolean,
|
||||
numer: AnyParseNode,
|
||||
denom: AnyParseNode,
|
||||
hasBarLine: boolean,
|
||||
leftDelim: ?string,
|
||||
rightDelim: ?string,
|
||||
size: StyleStr | "auto",
|
||||
barSize: Measurement | null,
|
||||
|},
|
||||
"horizBrace": {|
|
||||
type: "horizBrace",
|
||||
@@ -276,41 +264,29 @@ type ParseNodeTypes = {
|
||||
type: "htmlmathml",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "htmlmathml",
|
||||
html: AnyParseNode[],
|
||||
mathml: AnyParseNode[],
|
||||
|},
|
||||
html: AnyParseNode[],
|
||||
mathml: AnyParseNode[],
|
||||
|},
|
||||
"infix": {|
|
||||
type: "infix",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "infix",
|
||||
replaceWith: string,
|
||||
sizeNode?: ParseNode<"size">,
|
||||
token: ?Token,
|
||||
|},
|
||||
replaceWith: string,
|
||||
sizeNode?: ParseNode<"size">,
|
||||
token: ?Token,
|
||||
|},
|
||||
"kern": {|
|
||||
type: "kern",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "kern",
|
||||
dimension: Measurement,
|
||||
|},
|
||||
dimension: Measurement,
|
||||
|},
|
||||
"lap": {|
|
||||
type: "lap",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "lap",
|
||||
alignment: string,
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
alignment: string,
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
"leftright": {|
|
||||
type: "leftright",
|
||||
@@ -352,19 +328,13 @@ type ParseNodeTypes = {
|
||||
type: "operatorname",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "operatorname",
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
body: AnyParseNode[],
|
||||
|},
|
||||
"overline": {|
|
||||
type: "overline",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "overline",
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
"phantom": {|
|
||||
type: "phantom",
|
||||
@@ -388,63 +358,44 @@ type ParseNodeTypes = {
|
||||
type: "raisebox",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "raisebox",
|
||||
dy: ParseNode<"size">,
|
||||
body: AnyParseNode,
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
dy: ParseNode<"size">,
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
"rule": {|
|
||||
type: "rule",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "rule",
|
||||
shift: ?Measurement,
|
||||
width: Measurement,
|
||||
height: Measurement,
|
||||
|},
|
||||
shift: ?Measurement,
|
||||
width: Measurement,
|
||||
height: Measurement,
|
||||
|},
|
||||
"sizing": {|
|
||||
type: "sizing",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "sizing",
|
||||
size: number,
|
||||
value: AnyParseNode[],
|
||||
|},
|
||||
size: number,
|
||||
body: AnyParseNode[],
|
||||
|},
|
||||
"smash": {|
|
||||
type: "smash",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "smash",
|
||||
body: AnyParseNode,
|
||||
smashHeight: boolean,
|
||||
smashDepth: boolean,
|
||||
|},
|
||||
body: AnyParseNode,
|
||||
smashHeight: boolean,
|
||||
smashDepth: boolean,
|
||||
|},
|
||||
"sqrt": {|
|
||||
type: "sqrt",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "sqrt",
|
||||
body: AnyParseNode,
|
||||
index: ?AnyParseNode,
|
||||
|},
|
||||
body: AnyParseNode,
|
||||
index: ?AnyParseNode,
|
||||
|},
|
||||
"underline": {|
|
||||
type: "underline",
|
||||
mode: Mode,
|
||||
loc?: ?SourceLocation,
|
||||
value: {|
|
||||
type: "underline",
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
body: AnyParseNode,
|
||||
|},
|
||||
"xArrow": {|
|
||||
type: "xArrow",
|
||||
|
@@ -104,8 +104,8 @@ const getBaseElem = function(group: AnyParseNode): AnyParseNode {
|
||||
return group;
|
||||
}
|
||||
} else if (group.type === "color") {
|
||||
if (group.value.value.length === 1) {
|
||||
return getBaseElem(group.value.value[0]);
|
||||
if (group.body.length === 1) {
|
||||
return getBaseElem(group.body[0]);
|
||||
} else {
|
||||
return group;
|
||||
}
|
||||
|
Reference in New Issue
Block a user