mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-08 12:38:39 +00:00
Support \tag, \tag*, and \gdef (#1309)
* Tag sketch * Drop objectAssign; already using Object.assign elsewhere * Basic \gdef support * Bug fix * Finish \tag * MathML numbers equations with <mlabeledtr> * Fix flow bugs * \gdef tests * Add basic \tag tests * Screenshot test for \tag * \tag* test * Add missing file * Bug fix screenshot * Major refactor * Represent tag at top level of parse tree, requiring less hackery * No more \@tag function; it was essentially just doing \text * Wrap tag in group so e.g. ( and ) are formatted the same * Add `feed` method to MacroExpander for multiple inputs (for tag) * Bug fixes in buildHTML, makeTextRow, _getBuilt (for display mode) * Remove excess <mrow> wrapper when unnecessary * Update screenshot from tag being wrapped in group * Add maxExpand limit
This commit is contained in:
committed by
Kevin Barabash
parent
99b2afa935
commit
a0ddad338e
@@ -209,32 +209,30 @@ exports[`A MathML builder should render boldsymbol with the correct mathvariants
|
||||
<math>
|
||||
<semantics>
|
||||
<mrow>
|
||||
<mrow>
|
||||
<mi mathvariant="bold-italic">
|
||||
A
|
||||
</mi>
|
||||
<mi mathvariant="bold-italic">
|
||||
x
|
||||
</mi>
|
||||
<mn mathvariant="bold-italic">
|
||||
2
|
||||
</mn>
|
||||
<mi mathvariant="bold-italic">
|
||||
k
|
||||
</mi>
|
||||
<mi mathvariant="bold-italic">
|
||||
ω
|
||||
</mi>
|
||||
<mi mathvariant="bold-italic">
|
||||
Ω
|
||||
</mi>
|
||||
<mi mathvariant="bold-italic">
|
||||
ı
|
||||
</mi>
|
||||
<mo mathvariant="bold-italic">
|
||||
+
|
||||
</mo>
|
||||
</mrow>
|
||||
<mi mathvariant="bold-italic">
|
||||
A
|
||||
</mi>
|
||||
<mi mathvariant="bold-italic">
|
||||
x
|
||||
</mi>
|
||||
<mn mathvariant="bold-italic">
|
||||
2
|
||||
</mn>
|
||||
<mi mathvariant="bold-italic">
|
||||
k
|
||||
</mi>
|
||||
<mi mathvariant="bold-italic">
|
||||
ω
|
||||
</mi>
|
||||
<mi mathvariant="bold-italic">
|
||||
Ω
|
||||
</mi>
|
||||
<mi mathvariant="bold-italic">
|
||||
ı
|
||||
</mi>
|
||||
<mo mathvariant="bold-italic">
|
||||
+
|
||||
</mo>
|
||||
</mrow>
|
||||
<annotation encoding="application/x-tex">
|
||||
\\boldsymbol{Ax2k\\omega\\Omega\\imath+}
|
||||
@@ -296,35 +294,33 @@ 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>
|
||||
<msubsup>
|
||||
<mo>
|
||||
∑
|
||||
</mo>
|
||||
<mrow>
|
||||
<mi>
|
||||
k
|
||||
</mi>
|
||||
</msup>
|
||||
</mrow>
|
||||
<mo>
|
||||
=
|
||||
</mo>
|
||||
<mn>
|
||||
0
|
||||
</mn>
|
||||
</mrow>
|
||||
<mi mathvariant="normal">
|
||||
∞
|
||||
</mi>
|
||||
</msubsup>
|
||||
<msup>
|
||||
<mi>
|
||||
x
|
||||
</mi>
|
||||
<mi>
|
||||
k
|
||||
</mi>
|
||||
</msup>
|
||||
</mrow>
|
||||
<annotation encoding="application/x-tex">
|
||||
\\mathchoice{D}{\\sum_{k = 0}^{\\infty} x^k}{S}{SS}
|
||||
@@ -391,12 +387,10 @@ exports[`A MathML builder should set href attribute for href appropriately 1`] =
|
||||
|
||||
<math>
|
||||
<semantics>
|
||||
<mrow>
|
||||
<mrow href="http://example.org">
|
||||
<mi>
|
||||
α
|
||||
</mi>
|
||||
</mrow>
|
||||
<mrow href="http://example.org">
|
||||
<mi>
|
||||
α
|
||||
</mi>
|
||||
</mrow>
|
||||
<annotation encoding="application/x-tex">
|
||||
\\href{http://example.org}{\\alpha}
|
||||
@@ -505,3 +499,55 @@ exports[`A MathML builder should use <munderover> for large operators 1`] = `
|
||||
</math>
|
||||
|
||||
`;
|
||||
|
||||
exports[`A MathML builder tags use <mlabeledtr> 1`] = `
|
||||
|
||||
<math>
|
||||
<semantics>
|
||||
<mtable side="right">
|
||||
<mlabeledtr>
|
||||
<mtd>
|
||||
<mrow>
|
||||
<mtext>
|
||||
(
|
||||
</mtext>
|
||||
<mrow>
|
||||
<mtext>
|
||||
h
|
||||
</mtext>
|
||||
<mtext>
|
||||
i
|
||||
</mtext>
|
||||
</mrow>
|
||||
<mtext>
|
||||
)
|
||||
</mtext>
|
||||
</mrow>
|
||||
</mtd>
|
||||
<mtd>
|
||||
<mrow>
|
||||
<mi>
|
||||
x
|
||||
</mi>
|
||||
<mo>
|
||||
+
|
||||
</mo>
|
||||
<msup>
|
||||
<mi>
|
||||
y
|
||||
</mi>
|
||||
<mn>
|
||||
2
|
||||
</mn>
|
||||
</msup>
|
||||
</mrow>
|
||||
</mtd>
|
||||
</mlabeledtr>
|
||||
</mtable>
|
||||
<annotation encoding="application/x-tex">
|
||||
\\tag{hi} x+y^2
|
||||
</annotation>
|
||||
</semantics>
|
||||
</math>
|
||||
|
||||
`;
|
||||
|
@@ -11,13 +11,18 @@ export const defaultSettings = new Settings({
|
||||
export const strictSettings = new Settings({strict: true});
|
||||
|
||||
export const _getBuilt = function(expr, settings = defaultSettings) {
|
||||
const rootNode = katex.__renderToDomTree(expr, settings);
|
||||
let rootNode = katex.__renderToDomTree(expr, settings);
|
||||
|
||||
if (rootNode.classes.indexOf('katex-error') >= 0) {
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
if (rootNode.classes.indexOf('katex-display') >= 0) {
|
||||
rootNode = rootNode.children[0];
|
||||
}
|
||||
|
||||
// grab the root node of the HTML rendering
|
||||
// rootNode.children[0] is the MathML rendering
|
||||
const builtHTML = rootNode.children[1];
|
||||
|
||||
// combine the non-strut children of all base spans
|
||||
|
@@ -2663,6 +2663,24 @@ describe("A macro expander", function() {
|
||||
// {"\\mode": "\\TextOrMath{text}{math}"});
|
||||
//});
|
||||
|
||||
it("\\gdef defines macros", function() {
|
||||
compareParseTree("\\gdef\\foo{x^2}\\foo+\\foo", "x^2+x^2");
|
||||
compareParseTree("\\gdef{\\foo}{x^2}\\foo+\\foo", "x^2+x^2");
|
||||
compareParseTree("\\gdef\\foo{hi}\\foo+\\text{\\foo}", "hi+\\text{hi}");
|
||||
compareParseTree("\\gdef\\foo#1{hi #1}\\text{\\foo{Alice}, \\foo{Bob}}",
|
||||
"\\text{hi Alice, hi Bob}");
|
||||
compareParseTree("\\gdef\\foo#1#2{(#1,#2)}\\foo 1 2+\\foo 3 4",
|
||||
"(1,2)+(3,4)");
|
||||
expect("\\gdef\\foo#2{}").toNotParse();
|
||||
expect("\\gdef\\foo#1#3{}").toNotParse();
|
||||
expect("\\gdef\\foo#1#2#3#4#5#6#7#8#9{}").toParse();
|
||||
expect("\\gdef\\foo#1#2#3#4#5#6#7#8#9#10{}").toNotParse();
|
||||
expect("\\gdef\\foo#{}").toNotParse();
|
||||
expect("\\gdef\\foo\\bar").toParse();
|
||||
expect("\\gdef{\\foo\\bar}{}").toNotParse();
|
||||
expect("\\gdef{}{}").toNotParse();
|
||||
});
|
||||
|
||||
// This may change in the future, if we support the extra features of
|
||||
// \hspace.
|
||||
it("should treat \\hspace, \\hskip like \\kern", function() {
|
||||
@@ -2681,6 +2699,30 @@ describe("A macro expander", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("\\tag support", function() {
|
||||
const displayMode = new Settings({displayMode: true});
|
||||
|
||||
it("should fail outside display mode", () => {
|
||||
expect("\\tag{hi}x+y").toNotParse();
|
||||
});
|
||||
|
||||
it("should fail with multiple tags", () => {
|
||||
expect("\\tag{1}\\tag{2}x+y").toNotParse(displayMode);
|
||||
});
|
||||
|
||||
it("should build", () => {
|
||||
expect("\\tag{hi}x+y").toBuild(displayMode);
|
||||
});
|
||||
|
||||
it("should ignore location of \\tag", () => {
|
||||
expect("\\tag{hi}x+y").toParseLike("x+y\\tag{hi}", displayMode);
|
||||
});
|
||||
|
||||
it("should handle \\tag* like \\tag", () => {
|
||||
expect("\\tag{hi}x+y").toParseLike("\\tag*{({hi})}x+y", displayMode);
|
||||
});
|
||||
});
|
||||
|
||||
describe("A parser taking String objects", function() {
|
||||
it("should not fail on an empty String object", function() {
|
||||
expect(new String("")).toParse();
|
||||
@@ -2862,6 +2904,20 @@ describe("The maxSize setting", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("The maxExpand setting", () => {
|
||||
it("should prevent expansion", () => {
|
||||
expect("\\gdef\\foo{1}\\foo").toParse();
|
||||
expect("\\gdef\\foo{1}\\foo").toParse(new Settings({maxExpand: 2}));
|
||||
expect("\\gdef\\foo{1}\\foo").toNotParse(new Settings({maxExpand: 1}));
|
||||
expect("\\gdef\\foo{1}\\foo").toNotParse(new Settings({maxExpand: 0}));
|
||||
});
|
||||
|
||||
it("should prevent infinite loops", () => {
|
||||
expect("\\gdef\\foo{\\foo}\\foo").toNotParse(
|
||||
new Settings({maxExpand: 10}));
|
||||
});
|
||||
});
|
||||
|
||||
describe("The \\mathchoice function", function() {
|
||||
const cmd = "\\sum_{k = 0}^{\\infty} x^k";
|
||||
|
||||
|
@@ -94,8 +94,13 @@ describe("A MathML builder", function() {
|
||||
.toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('accents turn into <mover accent="true"> in MathML', function() {
|
||||
it('accents turn into <mover accent="true"> in MathML', () => {
|
||||
expect(getMathML("über fiancée", {unicodeTextInMathMode: true}))
|
||||
.toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('tags use <mlabeledtr>', () => {
|
||||
expect(getMathML("\\tag{hi} x+y^2", {displayMode: true}))
|
||||
.toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
BIN
test/screenshotter/images/Tag-chrome.png
Normal file
BIN
test/screenshotter/images/Tag-chrome.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.4 KiB |
BIN
test/screenshotter/images/Tag-firefox.png
Normal file
BIN
test/screenshotter/images/Tag-firefox.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.4 KiB |
@@ -332,6 +332,9 @@ SvgReset:
|
||||
Symbols1: |
|
||||
\maltese\degree\pounds\$
|
||||
\text{\maltese\degree\pounds\textdollar}
|
||||
Tag:
|
||||
tex: \tag{$+$hi} \frac{x^2}{y}+x^{2^y}
|
||||
display: 1
|
||||
Text: \frac{a}{b}\text{c~ {ab} \ e}+fg
|
||||
TextSpace:
|
||||
\begin{array}{l}
|
||||
|
Reference in New Issue
Block a user