mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-05 11:18:39 +00:00
* Implement correct macros for liminf and limsup, fixes #111 * fix nits
This commit is contained in:
@@ -198,9 +198,19 @@ groupTypes.supsub = function(group, options) {
|
||||
if (isBrace) {
|
||||
nodeType = (isOver ? "mover" : "munder");
|
||||
} else if (!group.value.sub) {
|
||||
nodeType = "msup";
|
||||
const base = group.value.base;
|
||||
if (base && base.value.limits && options.style === Style.DISPLAY) {
|
||||
nodeType = "mover";
|
||||
} else {
|
||||
nodeType = "msup";
|
||||
}
|
||||
} else if (!group.value.sup) {
|
||||
nodeType = "msub";
|
||||
const base = group.value.base;
|
||||
if (base && base.value.limits && options.style === Style.DISPLAY) {
|
||||
nodeType = "munder";
|
||||
} else {
|
||||
nodeType = "msub";
|
||||
}
|
||||
} else {
|
||||
const base = group.value.base;
|
||||
if (base && base.value.limits && options.style === Style.DISPLAY) {
|
||||
|
@@ -181,8 +181,7 @@ defineFunction([
|
||||
|
||||
// Limits, not symbols
|
||||
defineFunction([
|
||||
"\\det", "\\gcd", "\\inf", "\\lim", "\\liminf", "\\limsup", "\\max",
|
||||
"\\min", "\\Pr", "\\sup",
|
||||
"\\det", "\\gcd", "\\inf", "\\lim", "\\max", "\\min", "\\Pr", "\\sup",
|
||||
], {
|
||||
numArgs: 0,
|
||||
}, function(context) {
|
||||
|
@@ -30,22 +30,27 @@ defineFunction({
|
||||
let mode = "";
|
||||
|
||||
// Consolidate Greek letter function names into symbol characters.
|
||||
const temp = html.buildExpression(group.value.value, options, true);
|
||||
const temp = html.buildExpression(
|
||||
group.value.value, options.withFontFamily("mathrm"), true);
|
||||
|
||||
// All we want from temp are the letters. With them, we'll
|
||||
// create a text operator similar to \tan or \cos.
|
||||
for (let i = 0; i < temp.length; i++) {
|
||||
letter = temp[i].value;
|
||||
for (const child of temp) {
|
||||
if (child instanceof domTree.symbolNode) {
|
||||
letter = child.value;
|
||||
|
||||
// In the amsopn package, \newmcodes@ changes four
|
||||
// characters, *-/:’, from math operators back into text.
|
||||
// Given what is in temp, we have to address two of them.
|
||||
letter = letter.replace(/\u2212/, "-"); // minus => hyphen
|
||||
letter = letter.replace(/\u2217/, "*");
|
||||
// In the amsopn package, \newmcodes@ changes four
|
||||
// characters, *-/:’, from math operators back into text.
|
||||
// Given what is in temp, we have to address two of them.
|
||||
letter = letter.replace(/\u2212/, "-"); // minus => hyphen
|
||||
letter = letter.replace(/\u2217/, "*");
|
||||
|
||||
// Use math mode for Greek letters
|
||||
mode = (/[\u0391-\u03D7]/.test(letter) ? "math" : "text");
|
||||
output.push(buildCommon.mathsym(letter, mode));
|
||||
// Use math mode for Greek letters
|
||||
mode = (/[\u0391-\u03D7]/.test(letter) ? "math" : "text");
|
||||
output.push(buildCommon.mathsym(letter, mode));
|
||||
} else {
|
||||
output.push(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
return buildCommon.makeSpan(["mop"], output, options);
|
||||
@@ -55,12 +60,11 @@ defineFunction({
|
||||
// The steps taken here are similar to the html version.
|
||||
let output = [];
|
||||
if (group.value.value.length > 0) {
|
||||
const temp = mml.buildExpression(group.value.value, options);
|
||||
const temp = mml.buildExpression(
|
||||
group.value.value, options.withFontFamily("mathrm"));
|
||||
|
||||
let word = temp.map(node => node.toText()).join("");
|
||||
|
||||
let word = "";
|
||||
for (let i = 0; i < temp.length; i++) {
|
||||
word += temp[i].children[0].text;
|
||||
}
|
||||
word = word.replace(/\u2212/g, "-");
|
||||
word = word.replace(/\u2217/g, "*");
|
||||
output = [new mathMLTree.TextNode(word)];
|
||||
|
@@ -399,3 +399,5 @@ defineMacro("\\approxcoloncolon",
|
||||
// macro turned into a propper defineSymbol in symbols.js. That way, the
|
||||
// MathML result will be much cleaner.
|
||||
defineMacro("\\notni", "\\not\\ni");
|
||||
defineMacro("\\limsup", "\\DOTSB\\mathop{\\operatorname{lim\\,sup}}\\limits");
|
||||
defineMacro("\\liminf", "\\DOTSB\\mathop{\\operatorname{lim\\,inf}}\\limits");
|
||||
|
@@ -93,6 +93,22 @@ class MathNode {
|
||||
|
||||
return markup;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the math node into a string, similar to innerText.
|
||||
*/
|
||||
toText(): string {
|
||||
if (this.type === "mspace") {
|
||||
if (this.attributes.width === "0.16667em") {
|
||||
return "\u2006";
|
||||
} else {
|
||||
// TODO: Use other space characters for different widths.
|
||||
// https://github.com/Khan/KaTeX/issues/1036
|
||||
return " ";
|
||||
}
|
||||
}
|
||||
return this.children.map(child => child.toText()).join("");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -118,6 +134,13 @@ class TextNode {
|
||||
toMarkup(): string {
|
||||
return utils.escape(this.text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the text node into a string (which is just the text iteself).
|
||||
*/
|
||||
toText(): string {
|
||||
return this.text;
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
|
@@ -21,7 +21,9 @@ function init() {
|
||||
}
|
||||
|
||||
var macros = {};
|
||||
var options = {};
|
||||
// TODO: Add toggle for displayMode.
|
||||
// https://github.com/Khan/KaTeX/issues/1035
|
||||
var options = {displayMode: true};
|
||||
var macroRegex = /(?:^\?|&)(?:\\|%5[Cc])([A-Za-z]+)=([^&]*)/g;
|
||||
var macroString = "";
|
||||
while ((match = macroRegex.exec(window.location.search)) !== null) {
|
||||
|
@@ -77,6 +77,76 @@ exports[`A MathML builder should make prime operators into <mo> nodes 1`] = `
|
||||
|
||||
`;
|
||||
|
||||
exports[`A MathML builder should output \\limsup_{x \\rightarrow \\infty} correctly in \\textstyle 1`] = `
|
||||
|
||||
<math>
|
||||
<semantics>
|
||||
<mrow>
|
||||
<msub>
|
||||
<mo>
|
||||
<mi mathvariant="normal">
|
||||
lim sup
|
||||
</mi>
|
||||
<mo>
|
||||
|
||||
</mo>
|
||||
</mo>
|
||||
<mrow>
|
||||
<mi>
|
||||
x
|
||||
</mi>
|
||||
<mo>
|
||||
→
|
||||
</mo>
|
||||
<mi mathvariant="normal">
|
||||
∞
|
||||
</mi>
|
||||
</mrow>
|
||||
</msub>
|
||||
</mrow>
|
||||
<annotation encoding="application/x-tex">
|
||||
\\limsup_{x \\rightarrow \\infty}
|
||||
</annotation>
|
||||
</semantics>
|
||||
</math>
|
||||
|
||||
`;
|
||||
|
||||
exports[`A MathML builder should output \\limsup_{x \\rightarrow \\infty} in displaymode correctly 1`] = `
|
||||
|
||||
<math>
|
||||
<semantics>
|
||||
<mrow>
|
||||
<munder>
|
||||
<mo>
|
||||
<mi mathvariant="normal">
|
||||
lim sup
|
||||
</mi>
|
||||
<mo>
|
||||
|
||||
</mo>
|
||||
</mo>
|
||||
<mrow>
|
||||
<mi>
|
||||
x
|
||||
</mi>
|
||||
<mo>
|
||||
→
|
||||
</mo>
|
||||
<mi mathvariant="normal">
|
||||
∞
|
||||
</mi>
|
||||
</mrow>
|
||||
</munder>
|
||||
</mrow>
|
||||
<annotation encoding="application/x-tex">
|
||||
\\limsup_{x \\rightarrow \\infty}
|
||||
</annotation>
|
||||
</semantics>
|
||||
</math>
|
||||
|
||||
`;
|
||||
|
||||
exports[`A MathML builder should render boldsymbol with the correct mathvariants 1`] = `
|
||||
|
||||
<math>
|
||||
|
@@ -2733,6 +2733,16 @@ describe("A macro expander", function() {
|
||||
expect("\\hspace{1em}").toParseLike("\\kern1em");
|
||||
expect("\\hspace*{1em}").toParseLike("\\kern1em");
|
||||
});
|
||||
|
||||
it("should expand \\limsup as expected", () => {
|
||||
expect("\\limsup")
|
||||
.toParseLike("\\mathop{\\operatorname{lim\\,sup}}\\limits");
|
||||
});
|
||||
|
||||
it("should expand \\liminf as expected", () => {
|
||||
expect("\\liminf")
|
||||
.toParseLike("\\mathop{\\operatorname{lim\\,inf}}\\limits");
|
||||
});
|
||||
});
|
||||
|
||||
describe("A parser taking String objects", function() {
|
||||
|
@@ -51,6 +51,19 @@ describe("A MathML builder", function() {
|
||||
expect(getMathML("\\textstyle\\sum_a^b")).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should output \\limsup_{x \\rightarrow \\infty} correctly in " +
|
||||
"\\textstyle", () => {
|
||||
const mathml = getMathML("\\limsup_{x \\rightarrow \\infty}");
|
||||
expect(mathml).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("should output \\limsup_{x \\rightarrow \\infty} in " +
|
||||
"displaymode correctly", () => {
|
||||
const settings = new Settings({displayMode: true});
|
||||
const mathml = getMathML("\\limsup_{x \\rightarrow \\infty}", settings);
|
||||
expect(mathml).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should use <mpadded> for raisebox', () => {
|
||||
expect(getMathML("\\raisebox{0.25em}{b}")).toMatchSnapshot();
|
||||
});
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 25 KiB |
Binary file not shown.
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 19 KiB |
@@ -195,8 +195,11 @@ OperatorName: |
|
||||
\operatorname{Gam ma}(z) + \operatorname{\Gamma}(z) + \operatorname{}x
|
||||
\end{matrix}
|
||||
OpLimits: |
|
||||
{\sin_2^2 \lim_2^2 \int_2^2 \sum_2^2}
|
||||
{\displaystyle \lim_2^2 \int_2^2 \intop_2^2 \sum_2^2}
|
||||
\begin{matrix}
|
||||
{\sin_2^2 \lim_2^2 \int_2^2 \sum_2^2}
|
||||
{\displaystyle \lim_2^2 \int_2^2 \intop_2^2 \sum_2^2} \\
|
||||
\limsup_{x \rightarrow \infty} x \stackrel{?}= \liminf_{x \rightarrow \infty} x
|
||||
\end{matrix}
|
||||
OverUnderline: x\underline{x}\underline{\underline{x}}\underline{x_{x_{x_x}}}\underline{x^{x^{x^x}}}\overline{x}\overline{x}\overline{x^{x^{x^x}}} \blue{\overline{\underline{x}}\underline{\overline{x}}}
|
||||
OverUnderset: |
|
||||
\begin{array}{l}
|
||||
|
Reference in New Issue
Block a user