Implements \mathchoice command (#969)

This PR implements `\mathchoice` function.
I once created PR on the wrong branch. Sorry for the mess.

This is particularly useful when one defines custom macro for "big operators".
For example:

```latex
\newcommand{\infdisj}{%
  \mathop{%
    \mathchoice{% display
      \bigvee\hspace{-2ex}\bigvee%
    }{          % inline
      \bigvee\hspace{-1.75ex}\bigvee%
    }{          % script
      \bigvee\hspace{-1.4ex}\bigvee%
    }{          % scriptscript
      \bigvee\hspace{-1ex}\bigvee%
}}}
```
This commit is contained in:
Hiromi Ishii
2017-11-22 21:34:05 +09:00
committed by Erik Demaine
parent 2d32263998
commit 6f1661f7da
8 changed files with 245 additions and 0 deletions

View File

@@ -566,3 +566,6 @@ defineFunction(["\\verb"], {
throw new ParseError(
"\\verb ended by end of line instead of matching delimiter");
});
// MathChoice
import "./functions/mathchoice";

View File

@@ -0,0 +1,57 @@
// @flow
import defineFunction, {ordargument} from "../defineFunction";
import buildCommon from "../buildCommon";
import mathMLTree from "../mathMLTree";
import Style from "../Style";
import * as html from "../buildHTML";
import * as mml from "../buildMathML";
const chooseMathStyle = (group, options) => {
const style = options.style;
if (style.size === Style.DISPLAY.size) {
return group.value.display;
} else if (style.size === Style.TEXT.size) {
return group.value.text;
} else if (style.size === Style.SCRIPT.size) {
return group.value.script;
} else if (style.size === Style.SCRIPTSCRIPT.size) {
return group.value.scriptscript;
}
return group.value.text;
};
defineFunction({
type: "mathchoice",
names: ["\\mathchoice"],
props: {
numArgs: 4,
},
handler: (context, args) => {
return {
type: "mathchoice",
display: ordargument(args[0]),
text: ordargument(args[1]),
script: ordargument(args[2]),
scriptscript: ordargument(args[3]),
};
},
htmlBuilder: (group, options) => {
const body = chooseMathStyle(group, options);
const elements = html.buildExpression(
body,
options,
false
);
return new buildCommon.makeFragment(elements);
},
mathmlBuilder: (group, options) => {
const body = chooseMathStyle(group, options);
const elements = mml.buildExpression(
body,
options,
false
);
return new mathMLTree.MathNode("mrow", elements);
},
});

View File

@@ -74,6 +74,149 @@ exports[`A MathML builder should make prime operators into <mo> nodes 1`] = `
`;
exports[`A MathML builder should render mathchoice as if there was nothing 1`] = `
<math>
<semantics>
<mrow>
<mstyle scriptlevel="0"
displaystyle="true"
>
<mrow>
<munderover>
<mo>
</mo>
<mrow>
<mi>
k
</mi>
<mo>
=
</mo>
<mn>
0
</mn>
</mrow>
<mi mathvariant="normal">
</mi>
</munderover>
<msup>
<mi>
x
</mi>
<mi>
k
</mi>
</msup>
</mrow>
</mstyle>
</mrow>
<annotation encoding="application/x-tex">
\\displaystyle\\mathchoice{\\sum_{k = 0}^{\\infty} x^k}{T}{S}{SS}
</annotation>
</semantics>
</math>
`;
exports[`A MathML builder should render mathchoice as if there was nothing 2`] = `
<math>
<semantics>
<mrow>
<mrow>
<msubsup>
<mo>
</mo>
<mrow>
<mi>
k
</mi>
<mo>
=
</mo>
<mn>
0
</mn>
</mrow>
<mi mathvariant="normal">
</mi>
</msubsup>
<msup>
<mi>
x
</mi>
<mi>
k
</mi>
</msup>
</mrow>
</mrow>
<annotation encoding="application/x-tex">
\\mathchoice{D}{\\sum_{k = 0}^{\\infty} x^k}{S}{SS}
</annotation>
</semantics>
</math>
`;
exports[`A MathML builder should render mathchoice as if there was nothing 3`] = `
<math>
<semantics>
<mrow>
<msub>
<mi>
x
</mi>
<mrow>
<mi>
T
</mi>
</mrow>
</msub>
</mrow>
<annotation encoding="application/x-tex">
x_{\\mathchoice{D}{T}{\\sum_{k = 0}^{\\infty} x^k}{SS}}
</annotation>
</semantics>
</math>
`;
exports[`A MathML builder should render mathchoice as if there was nothing 4`] = `
<math>
<semantics>
<mrow>
<msub>
<mi>
x
</mi>
<msub>
<mi>
y
</mi>
<mrow>
<mi>
T
</mi>
</mrow>
</msub>
</msub>
</mrow>
<annotation encoding="application/x-tex">
x_{y_{\\mathchoice{D}{T}{S}{\\sum_{k = 0}^{\\infty} x^k}}}
</annotation>
</semantics>
</math>
`;
exports[`A MathML builder should use <menclose> for colorbox 1`] = `
<math>

View File

@@ -2660,3 +2660,31 @@ describe("The maxSize setting", function() {
expect(built.style.borderTopWidth).toEqual("0em");
});
});
describe("The \\mathchoice function", function() {
const cmd = "\\sum_{k = 0}^{\\infty} x^k";
it("should render as if there is nothing other in display math", function() {
const plain = getBuilt("\\displaystyle" + cmd)[0];
const built = getBuilt(`\\displaystyle\\mathchoice{${cmd}}{T}{S}{SS}`)[0];
expect(built).toEqual(plain);
});
it("should render as if there is nothing other in text", function() {
const plain = getBuilt(cmd)[0];
const built = getBuilt(`\\mathchoice{D}{${cmd}}{S}{SS}`)[0];
expect(built).toEqual(plain);
});
it("should render as if there is nothing other in scriptstyle", function() {
const plain = getBuilt(`x_{${cmd}}`)[0];
const built = getBuilt(`x_{\\mathchoice{D}{T}{${cmd}}{SS}}`)[0];
expect(built).toEqual(plain);
});
it("should render as if there is nothing other in scriptscriptstyle", function() {
const plain = getBuilt(`x_{y_{${cmd}}}`)[0];
const built = getBuilt(`x_{y_{\\mathchoice{D}{T}{S}{${cmd}}}}`)[0];
expect(built).toEqual(plain);
});
});

View File

@@ -58,4 +58,16 @@ describe("A MathML builder", function() {
it('should use <menclose> for colorbox', () => {
expect(getMathML("\\colorbox{red}{b}")).toMatchSnapshot();
});
it('should render mathchoice as if there was nothing', () => {
const cmd = "\\sum_{k = 0}^{\\infty} x^k";
expect(getMathML(`\\displaystyle\\mathchoice{${cmd}}{T}{S}{SS}`))
.toMatchSnapshot();
expect(getMathML(`\\mathchoice{D}{${cmd}}{S}{SS}`))
.toMatchSnapshot();
expect(getMathML(`x_{\\mathchoice{D}{T}{${cmd}}{SS}}`))
.toMatchSnapshot();
expect(getMathML(`x_{y_{\\mathchoice{D}{T}{S}{${cmd}}}}`))
.toMatchSnapshot();
});
});

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

View File

@@ -144,6 +144,8 @@ LowerAccent: |
\end{matrix}
MathAtom: a\mathrel{\mathop{=}\limits^{\blue ?}}b
MathAtom2: \mathop{\overline{\mathrm{lim}}}\limits_{x\to\infty}f(x)
MathChoice: |
{\displaystyle\mathchoice{D}{T}{S}{SS}} {\textstyle\mathchoice{D}{T}{S}{SS}} {\scriptstyle \mathchoice{D}{T}{S}{SS}} {\scriptscriptstyle\mathchoice{D}{T}{S}{SS}} \displaystyle X_{\mathchoice{D}{T}{S}{SS}_{\mathchoice{D}{T}{S}{SS}}}
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}