Support \mathop, \mathrel, \mathbin, \mathpunct, etc. class commands.

These commands set their arguments in a given TeX math class. Use
the existing "op" type for \mathop (to support \limits); introduce
a new "mclass" type for the other classes.

Fixes #482. Tests borrowed from #485 (cbreeden).
This commit is contained in:
Eddie Kohler 2016-11-23 08:52:10 -05:00
parent 982e7be597
commit 6bb62b11b4
8 changed files with 65 additions and 37 deletions

View File

@ -786,6 +786,11 @@ groupTypes.op = function(group, options) {
// The slant of the symbol is just its italic correction.
slant = base.italic;
} else if (group.value.value) {
// If this is a list, compose that list.
var inner = buildExpression(group.value.value, options, true);
base = makeSpan(["mop"], inner, options);
} else {
// Otherwise, this is a text operator. Build the text from the
// operator's name.
@ -1399,6 +1404,12 @@ groupTypes.phantom = function(group, options) {
return new buildCommon.makeFragment(elements);
};
groupTypes.mclass = function(group, options) {
var elements = buildExpression(group.value.value, options, true);
return makeSpan([group.value.mclass], elements, options);
};
/**
* buildGroup is the function that takes a group and calls the correct groupType
* function for it. It also handles the interaction of size and style changes

View File

@ -316,7 +316,7 @@ groupTypes.spacing = function(group) {
return node;
};
groupTypes.op = function(group) {
groupTypes.op = function(group, options) {
var node;
// TODO(emily): handle big operators using the `largeop` attribute
@ -325,6 +325,10 @@ groupTypes.op = function(group) {
// This is a symbol. Just add the symbol.
node = new mathMLTree.MathNode(
"mo", [makeText(group.value.body, group.mode)]);
} else if (group.value.value) {
// This is an operator with children. Add them.
node = new mathMLTree.MathNode(
"mo", buildExpression(group.value.value, options));
} else {
// This is a text operator. Add all of the characters from the
// operator's name.
@ -475,6 +479,11 @@ groupTypes.phantom = function(group, options) {
return new mathMLTree.MathNode("mphantom", inner);
};
groupTypes.mclass = function(group, options) {
var inner = buildExpression(group.value.value, options);
return new mathMLTree.MathNode("mstyle", inner);
};
/**
* Takes a list of nodes, builds them, and returns a list of the generated
* MathML nodes. A little simpler than the HTML version because we don't do any

View File

@ -100,6 +100,16 @@ function defineFunction(names, props, handler) {
}
}
// Since the corresponding buildHTML/buildMathML function expects a
// list of elements, we normalize for different kinds of arguments
var ordargument = function(arg) {
if (arg.type === "ordgroup") {
return arg.value;
} else {
return [arg];
}
};
// A normal square root
defineFunction("\\sqrt", {
numArgs: 1,
@ -121,19 +131,9 @@ defineFunction("\\text", {
greediness: 2,
}, function(context, args) {
var body = args[0];
// Since the corresponding buildHTML/buildMathML function expects a
// list of elements, we normalize for different kinds of arguments
// TODO(emily): maybe this should be done somewhere else
var inner;
if (body.type === "ordgroup") {
inner = body.value;
} else {
inner = [body];
}
return {
type: "text",
body: inner,
body: ordargument(body),
};
});
@ -146,18 +146,10 @@ defineFunction("\\color", {
}, function(context, args) {
var color = args[0];
var body = args[1];
// Normalize the different kinds of bodies (see \text above)
var inner;
if (body.type === "ordgroup") {
inner = body.value;
} else {
inner = [body];
}
return {
type: "color",
color: color.value,
value: inner,
value: ordargument(body),
};
});
@ -223,16 +215,24 @@ defineFunction("\\phantom", {
numArgs: 1,
}, function(context, args) {
var body = args[0];
var inner;
if (body.type === "ordgroup") {
inner = body.value;
} else {
inner = [body];
}
return {
type: "phantom",
value: inner,
value: ordargument(body),
};
});
// Math class commands except \mathop
defineFunction([
"\\mathord", "\\mathbin", "\\mathrel", "\\mathopen",
"\\mathclose", "\\mathpunct", "\\mathinner",
], {
numArgs: 1,
}, function(context, args) {
var body = args[0];
return {
type: "mclass",
mclass: "m" + context.funcName.substr(5),
value: ordargument(body),
};
});
@ -298,17 +298,10 @@ defineFunction([
greediness: 3,
}, function(context, args) {
var body = args[0];
var atoms;
if (body.type === "ordgroup") {
atoms = body.value;
} else {
atoms = [body];
}
return {
type: "color",
color: "katex-" + context.funcName.slice(1),
value: atoms,
value: ordargument(body),
};
});
@ -378,6 +371,19 @@ defineFunction([
};
});
// \mathop class command
defineFunction("\\mathop", {
numArgs: 1,
}, function(context, args) {
var body = args[0];
return {
type: "op",
limits: false,
symbol: false,
value: ordargument(body),
};
});
// Fractions
defineFunction([
"\\dfrac", "\\frac", "\\tfrac",

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

View File

@ -79,6 +79,8 @@ LeftRightStyleSizing: |
LimitControls: |
\displaystyle\int\limits_2^3 3x^2\,dx + \sum\nolimits^n_{i=1}i +
\textstyle\int\limits_x^y z
MathAtom: a\mathrel{\mathop{=}\limits^{\blue ?}}b
MathAtom2: \mathop{\overline\mathrm{lim}}\limits_{x\to\infty}f(x)
MathDefaultFonts: Ax2k\breve{a}\omega\Omega\imath+\KaTeX
MathBb: \mathbb{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}
MathBf: \mathbf{Ax2k\breve{a}\omega\Omega\imath+\KaTeX}