feat: Support {CD} (#2396)

* Support {CD}

* Edit screenshotter test to fit on one page

* Update screenshots

* Remove bogus Safari screenshot

* Edit documentation to avoid tag conflicts and explain delimiters

* Add type annotations

* Add bogus safari screenshot

* Update with real Safari screenshot

* Set label vertical alignment

* Revise call to parseExpression() per PR 2085 changes to macro parsing

* Update Firefox screenshot

* Pick up review comments

* Add unit tests and snapshot.

* Tighten up label collection.

* Better loop index

* remove extra space

* Picked up comments. Added a parse check. Added a test.

Co-authored-by: ylemkimon <y@ylem.kim>
Co-authored-by: Kevin Barabash <kevinb@khanacademy.org>
Co-authored-by: Kevin Barabash <kevinb7@gmail.com>
This commit is contained in:
Ron Kok
2020-12-27 10:45:31 -08:00
committed by GitHub
parent b34175bd92
commit 75a3af9725
17 changed files with 652 additions and 14 deletions

View File

@@ -204,6 +204,211 @@ exports[`A MathML builder normal spaces render normally 1`] = `
</math>
`;
exports[`A MathML builder should build the CD environment properly 1`] = `
<math xmlns="http://www.w3.org/1998/Math/MathML"
display="block"
>
<semantics>
<mtable rowspacing="0.2500em"
columnalign="center center center"
columnspacing="0.5em"
>
<mtr>
<mtd>
<mstyle scriptlevel="0"
displaystyle="true"
>
<mi>
A
</mi>
</mstyle>
</mtd>
<mtd>
<mstyle scriptlevel="0"
displaystyle="true"
>
<munderover>
<mo stretchy="true"
minsize="3.0em"
>
</mo>
<mpadded width="+0.6em"
lspace="0.3em"
>
<mrow>
</mrow>
</mpadded>
<mpadded width="+0.6em"
lspace="0.3em"
>
<mi>
a
</mi>
</mpadded>
</munderover>
</mstyle>
</mtd>
<mtd>
<mstyle scriptlevel="0"
displaystyle="true"
>
<mi>
B
</mi>
</mstyle>
</mtd>
</mtr>
<mtr>
<mtd>
<mstyle scriptlevel="0"
displaystyle="true"
>
<mrow>
<mrow>
<mstyle displaystyle="false"
scriptlevel="1"
>
<mpadded width="0"
lspace="-1width"
voffset="0.7em"
>
<mrow>
<mrow>
</mrow>
</mrow>
</mpadded>
</mstyle>
<mo fence="false"
stretchy="true"
minsize="1.8em"
maxsize="1.8em"
>
</mo>
<mstyle displaystyle="false"
scriptlevel="1"
>
<mpadded width="0"
voffset="0.7em"
>
<mrow>
<mi>
b
</mi>
</mrow>
</mpadded>
</mstyle>
</mrow>
</mrow>
</mstyle>
</mtd>
<mtd>
<mstyle scriptlevel="0"
displaystyle="true"
>
</mstyle>
</mtd>
<mtd>
<mstyle scriptlevel="0"
displaystyle="true"
>
<mrow>
<mrow>
<mstyle displaystyle="false"
scriptlevel="1"
>
<mpadded width="0"
lspace="-1width"
voffset="0.7em"
>
<mrow>
<mrow>
</mrow>
</mrow>
</mpadded>
</mstyle>
<mo fence="false"
stretchy="true"
minsize="1.8em"
maxsize="1.8em"
>
</mo>
<mstyle displaystyle="false"
scriptlevel="1"
>
<mpadded width="0"
voffset="0.7em"
>
<mrow>
<mi>
c
</mi>
</mrow>
</mpadded>
</mstyle>
</mrow>
</mrow>
</mstyle>
</mtd>
</mtr>
<mtr>
<mtd>
<mstyle scriptlevel="0"
displaystyle="true"
>
<mi>
C
</mi>
</mstyle>
</mtd>
<mtd>
<mstyle scriptlevel="0"
displaystyle="true"
>
<munderover>
<mo stretchy="true"
minsize="3.0em"
>
</mo>
<mpadded width="+0.6em"
lspace="0.3em"
>
<mrow>
</mrow>
</mpadded>
<mpadded width="+0.6em"
lspace="0.3em"
>
<mi>
d
</mi>
</mpadded>
</munderover>
</mstyle>
</mtd>
<mtd>
<mstyle scriptlevel="0"
displaystyle="true"
>
<mi>
D
</mi>
</mstyle>
</mtd>
</mtr>
<mtr>
</mtr>
</mtable>
<annotation encoding="application/x-tex">
\\begin{CD} A @&gt;a&gt;&gt; B\\\\ @VVbV @VVcV\\\\ C @&gt;d&gt;&gt; D \\end{CD}
</annotation>
</semantics>
</math>
`;
exports[`A MathML builder should concatenate digits into single <mn> 1`] = `
<math xmlns="http://www.w3.org/1998/Math/MathML">
<semantics>

View File

@@ -2778,6 +2778,7 @@ describe("AMS environments", function() {
expect`\begin{alignat*}{2}10&x+ &3&y = 2\\3&x+&13&y = 4\end{alignat*}`.not.toParse(nonstrictSettings);
expect`\begin{equation}a=b+c\end{equation}`.not.toParse(nonstrictSettings);
expect`\begin{split}a &=b+c\\&=e+f\end{split}`.not.toParse(nonstrictSettings);
expect`\begin{CD}A @>a>> B \\@VbVV @AAcA\\C @= D\end{CD}`.not.toParse(nonstrictSettings);
});
const nonStrictDisplay = new Settings({displayMode: true, strict: false});
@@ -2791,6 +2792,7 @@ describe("AMS environments", function() {
expect`\begin{equation}a=b+c\end{equation}`.toBuild(nonStrictDisplay);
expect`\begin{equation}\begin{split}a &=b+c\\&=e+f\end{split}\end{equation}`.toBuild(nonStrictDisplay);
expect`\begin{split}a &=b+c\\&=e+f\end{split}`.toBuild(nonStrictDisplay);
expect`\begin{CD}A @<a<< B @>>b> C @>>> D\\@. @| @AcAA @VVdV \\@. E @= F @>>> G\end{CD}`.toBuild(nonStrictDisplay);
});
it("{equation} should fail if argument contains two rows.", () => {
@@ -2807,6 +2809,29 @@ describe("AMS environments", function() {
});
});
describe("The CD environment", function() {
it("should fail if not is display mode", function() {
expect(`\\begin{CD}A @<a<< B @>>b> C @>>> D\\\\@. @| @AcAA @VVdV \\\\@. E @= F @>>> G\\end{CD}`).not.toParse(
new Settings({displayMode: false, strict: false})
);
});
const displaySettings = new Settings({displayMode: true, strict: false});
it("should fail if the character after '@' is not in <>AV=|.", function() {
expect(`\\begin{CD}A @X<a<< B @>>b> C @>>> D\\\\@. @| @AcAA @VVdV \\\\@. E @= F @>>> G\\end{CD}`).not.toParse(displaySettings);
});
it("should fail if an arrow does not have its final character.", function() {
expect(`\\begin{CD}A @<a< B @>>b> C @>>> D\\\\@. @| @AcAA @VVdV \\\\@. E @= F @>>> G\\end{CD}`).not.toParse(displaySettings);
expect(`\\begin{CD}A @<a<< B @>>b C @>>> D\\\\@. @| @AcAA @VVdV \\\\@. E @= F @>>> G\\end{CD}`).not.toParse(displaySettings);
});
it("should fail without an \\\\end.", function() {
expect(`\\begin{CD}A @<a<< B @>>b> C @>>> D\\\\@. @| @AcAA @VVdV \\\\@. E @= F @>>> G`).not.toParse(displaySettings);
});
it("should succeed without the flaws noted above.", function() {
expect(`\\begin{CD}A @<a<< B @>>b> C @>>> D\\\\@. @| @AcAA @VVdV \\\\@. E @= F @>>> G\\end{CD}`).toBuild(displaySettings);
});
});
describe("operatorname support", function() {
it("should not fail", function() {
expect("\\operatorname{x*Π∑\\Pi\\sum\\frac a b}").toBuild();

View File

@@ -79,6 +79,13 @@ describe("A MathML builder", function() {
expect(getMathML("\\colorbox{red}{b}")).toMatchSnapshot();
});
it('should build the CD environment properly', () => {
const displaySettings = new Settings({displayMode: true, strict: false});
const mathml = getMathML("\\begin{CD} A @>a>> B\\\\ @VVbV @VVcV\\\\" +
" C @>d>> D \\end{CD}", displaySettings);
expect(mathml).toMatchSnapshot();
});
it('should set href attribute for href appropriately', () => {
expect(
getMathML("\\href{http://example.org}{\\alpha}", new Settings({trust: true})),

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -86,6 +86,9 @@ Cases: |
a &\text{if } b \\
c &\text{if } d
\end{rcases}⇒…
CD:
tex: \begin{CD} A @<a<< B @>>b> C \\ @| @AcAA @VVdV \\ D @= E @>>> F \end{CD}
display: 1
Colors:
tex: \blue{a}\textcolor{#0f0}{b}\textcolor{red}{c}
nolatex: different syntax and different scope