extract color and text commands into their own files in functions sub-directory (#998)

This commit is contained in:
Kevin Barabash
2017-11-27 23:50:07 -05:00
committed by GitHub
parent 98203ad6ba
commit 1b20414526
5 changed files with 161 additions and 127 deletions

View File

@@ -305,28 +305,6 @@ groupTypes.ordgroup = function(group, options) {
);
};
groupTypes.text = function(group, options) {
const newOptions = options.withFont(group.value.font);
const inner = buildExpression(group.value.body, newOptions, true);
buildCommon.tryCombineChars(inner);
return makeSpan(["mord", "text"],
inner, newOptions);
};
groupTypes.color = function(group, options) {
const elements = buildExpression(
group.value.value,
options.withColor(group.value.color),
false
);
// \color isn't supposed to affect the type of the elements it contains.
// To accomplish this, we wrap the results in a fragment, so the inner
// elements will be able to directly interact with their neighbors. For
// example, `\color{red}{2 +} 3` has the same spacing as `2 + 3`
return new buildCommon.makeFragment(elements);
};
groupTypes.supsub = function(group, options) {
// Superscript and subscripts are handled in the TeXbook on page
// 445-446, rules 18(a-f).

View File

@@ -158,45 +158,6 @@ groupTypes.ordgroup = function(group, options) {
return node;
};
groupTypes.text = function(group, options) {
const body = group.value.body;
// Convert each element of the body into MathML, and combine consecutive
// <mtext> outputs into a single <mtext> tag. In this way, we don't
// nest non-text items (e.g., $nested-math$) within an <mtext>.
const inner = [];
let currentText = null;
for (let i = 0; i < body.length; i++) {
const group = buildGroup(body[i], options);
if (group.type === 'mtext' && currentText != null) {
Array.prototype.push.apply(currentText.children, group.children);
} else {
inner.push(group);
if (group.type === 'mtext') {
currentText = group;
}
}
}
// If there is a single tag in the end (presumably <mtext>),
// just return it. Otherwise, wrap them in an <mrow>.
if (inner.length === 1) {
return inner[0];
} else {
return new mathMLTree.MathNode("mrow", inner);
}
};
groupTypes.color = function(group, options) {
const inner = buildExpression(group.value.value, options);
const node = new mathMLTree.MathNode("mstyle", inner);
node.setAttribute("mathcolor", group.value.color);
return node;
};
groupTypes.supsub = function(group, options) {
// Is the inner group a relevant horizonal brace?
let isBrace = false;

View File

@@ -40,45 +40,9 @@ defineFunction(["\\sqrt"], {
};
});
// Non-mathy text, possibly in a font
const textFunctionFonts = {
"\\text": undefined, "\\textrm": "mathrm", "\\textsf": "mathsf",
"\\texttt": "mathtt", "\\textnormal": "mathrm", "\\textbf": "mathbf",
"\\textit": "textit",
};
import "./functions/color";
defineFunction([
"\\text", "\\textrm", "\\textsf", "\\texttt", "\\textnormal",
"\\textbf", "\\textit",
], {
numArgs: 1,
argTypes: ["text"],
greediness: 2,
allowedInText: true,
}, function(context, args) {
const body = args[0];
return {
type: "text",
body: ordargument(body),
font: textFunctionFonts[context.funcName],
};
});
// A two-argument custom color
defineFunction(["\\textcolor"], {
numArgs: 2,
allowedInText: true,
greediness: 3,
argTypes: ["color", "original"],
}, function(context, args) {
const color = args[0];
const body = args[1];
return {
type: "color",
color: color.value,
value: ordargument(body),
};
});
import "./functions/text";
// \color is handled in Parser.js's parseImplicitGroup
defineFunction(["\\color"], {
@@ -185,34 +149,6 @@ const fontAliases = {
"\\frak": "\\mathfrak",
};
// Single-argument color functions
defineFunction([
"\\blue", "\\orange", "\\pink", "\\red",
"\\green", "\\gray", "\\purple",
"\\blueA", "\\blueB", "\\blueC", "\\blueD", "\\blueE",
"\\tealA", "\\tealB", "\\tealC", "\\tealD", "\\tealE",
"\\greenA", "\\greenB", "\\greenC", "\\greenD", "\\greenE",
"\\goldA", "\\goldB", "\\goldC", "\\goldD", "\\goldE",
"\\redA", "\\redB", "\\redC", "\\redD", "\\redE",
"\\maroonA", "\\maroonB", "\\maroonC", "\\maroonD", "\\maroonE",
"\\purpleA", "\\purpleB", "\\purpleC", "\\purpleD", "\\purpleE",
"\\mintA", "\\mintB", "\\mintC",
"\\grayA", "\\grayB", "\\grayC", "\\grayD", "\\grayE",
"\\grayF", "\\grayG", "\\grayH", "\\grayI",
"\\kaBlue", "\\kaGreen",
], {
numArgs: 1,
allowedInText: true,
greediness: 3,
}, function(context, args) {
const body = args[0];
return {
type: "color",
color: "katex-" + context.funcName.slice(1),
value: ordargument(body),
};
});
const singleCharIntegrals: {[string]: string} = {
"\u222b": "\\int",
"\u222c": "\\iint",

88
src/functions/color.js Normal file
View File

@@ -0,0 +1,88 @@
// @flow
import defineFunction, {ordargument} from "../defineFunction";
import buildCommon from "../buildCommon";
import mathMLTree from "../mathMLTree";
import * as html from "../buildHTML";
import * as mml from "../buildMathML";
const htmlBuilder = (group, options) => {
const elements = html.buildExpression(
group.value.value,
options.withColor(group.value.color),
false
);
// \color isn't supposed to affect the type of the elements it contains.
// To accomplish this, we wrap the results in a fragment, so the inner
// elements will be able to directly interact with their neighbors. For
// example, `\color{red}{2 +} 3` has the same spacing as `2 + 3`
return new buildCommon.makeFragment(elements);
};
const mathmlBuilder = (group, options) => {
const inner = mml.buildExpression(group.value.value, options);
const node = new mathMLTree.MathNode("mstyle", inner);
node.setAttribute("mathcolor", group.value.color);
return node;
};
defineFunction({
type: "color",
names: ["\\textcolor"],
props: {
numArgs: 2,
allowedInText: true,
greediness: 3,
argTypes: ["color", "original"],
},
handler(context, args) {
const color = args[0];
const body = args[1];
return {
type: "color",
color: color.value,
value: ordargument(body),
};
},
htmlBuilder,
mathmlBuilder,
});
// TODO(kevinb): define these using macros
defineFunction({
type: "color",
names: [
"\\blue", "\\orange", "\\pink", "\\red",
"\\green", "\\gray", "\\purple",
"\\blueA", "\\blueB", "\\blueC", "\\blueD", "\\blueE",
"\\tealA", "\\tealB", "\\tealC", "\\tealD", "\\tealE",
"\\greenA", "\\greenB", "\\greenC", "\\greenD", "\\greenE",
"\\goldA", "\\goldB", "\\goldC", "\\goldD", "\\goldE",
"\\redA", "\\redB", "\\redC", "\\redD", "\\redE",
"\\maroonA", "\\maroonB", "\\maroonC", "\\maroonD", "\\maroonE",
"\\purpleA", "\\purpleB", "\\purpleC", "\\purpleD", "\\purpleE",
"\\mintA", "\\mintB", "\\mintC",
"\\grayA", "\\grayB", "\\grayC", "\\grayD", "\\grayE",
"\\grayF", "\\grayG", "\\grayH", "\\grayI",
"\\kaBlue", "\\kaGreen",
],
props: {
numArgs: 1,
allowedInText: true,
greediness: 3,
},
handler(context, args) {
const body = args[0];
return {
type: "color",
color: "katex-" + context.funcName.slice(1),
value: ordargument(body),
};
},
htmlBuilder,
mathmlBuilder,
});

71
src/functions/text.js Normal file
View File

@@ -0,0 +1,71 @@
// @flow
import defineFunction, {ordargument} from "../defineFunction";
import buildCommon from "../buildCommon";
import mathMLTree from "../mathMLTree";
import * as html from "../buildHTML";
import * as mml from "../buildMathML";
// Non-mathy text, possibly in a font
const textFunctionFonts = {
"\\text": undefined, "\\textrm": "mathrm", "\\textsf": "mathsf",
"\\texttt": "mathtt", "\\textnormal": "mathrm", "\\textbf": "mathbf",
"\\textit": "textit",
};
defineFunction({
type: "text",
names: [
"\\text", "\\textrm", "\\textsf", "\\texttt", "\\textnormal",
"\\textbf", "\\textit",
],
props: {
numArgs: 1,
argTypes: ["text"],
greediness: 2,
allowedInText: true,
},
handler(context, args) {
const body = args[0];
return {
type: "text",
body: ordargument(body),
font: textFunctionFonts[context.funcName],
};
},
htmlBuilder(group, options) {
const newOptions = options.withFont(group.value.font);
const inner = html.buildExpression(group.value.body, newOptions, true);
buildCommon.tryCombineChars(inner);
return buildCommon.makeSpan(["mord", "text"],
inner, newOptions);
},
mathmlBuilder(group, options) {
const body = group.value.body;
// Convert each element of the body into MathML, and combine consecutive
// <mtext> outputs into a single <mtext> tag. In this way, we don't
// nest non-text items (e.g., $nested-math$) within an <mtext>.
const inner = [];
let currentText = null;
for (let i = 0; i < body.length; i++) {
const group = mml.buildGroup(body[i], options);
if (group.type === 'mtext' && currentText != null) {
Array.prototype.push.apply(currentText.children, group.children);
} else {
inner.push(group);
if (group.type === 'mtext') {
currentText = group;
}
}
}
// If there is a single tag in the end (presumably <mtext>),
// just return it. Otherwise, wrap them in an <mrow>.
if (inner.length === 1) {
return inner[0];
} else {
return new mathMLTree.MathNode("mrow", inner);
}
},
});