mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-08 20:48:41 +00:00
Automatic mrel/mbin spacing for \boldsymbol (#1388)
* Automatic mrel/mbin spacing for \boldsymbol Fix #1154 * Add test * Add missing mode * Separate out \boldsymbol support to correct flow types * Fix ternaries thanks to @ronkok's comment * Revert package-lock.json * Add screenshot test
This commit is contained in:
@@ -30,15 +30,15 @@ const fontAliases = {
|
||||
defineFunction({
|
||||
type: "font",
|
||||
names: [
|
||||
// styles
|
||||
"\\mathrm", "\\mathit", "\\mathbf", "\\boldsymbol",
|
||||
// styles, except \boldsymbol defined below
|
||||
"\\mathrm", "\\mathit", "\\mathbf",
|
||||
|
||||
// families
|
||||
"\\mathbb", "\\mathcal", "\\mathfrak", "\\mathscr", "\\mathsf",
|
||||
"\\mathtt",
|
||||
|
||||
// aliases
|
||||
"\\Bbb", "\\bold", "\\frak", "\\bm",
|
||||
// aliases, except \bm defined below
|
||||
"\\Bbb", "\\bold", "\\frak",
|
||||
],
|
||||
props: {
|
||||
numArgs: 1,
|
||||
@@ -53,13 +53,44 @@ defineFunction({
|
||||
return new ParseNode("font", {
|
||||
type: "font",
|
||||
font: func.slice(1),
|
||||
body: body,
|
||||
body,
|
||||
}, parser.mode);
|
||||
},
|
||||
htmlBuilder,
|
||||
mathmlBuilder,
|
||||
});
|
||||
|
||||
defineFunction({
|
||||
type: "mclass",
|
||||
names: ["\\boldsymbol", "\\bm"],
|
||||
props: {
|
||||
numArgs: 1,
|
||||
greediness: 2,
|
||||
},
|
||||
handler: ({parser}, args) => {
|
||||
const body = args[0];
|
||||
// amsbsy.sty's \boldsymbol inherits the argument's bin|rel|ord status
|
||||
// (similar to \stackrel in functions/mclass.js)
|
||||
let mclass = "mord";
|
||||
const atomType = (body.type === "ordgroup" && body.value.length ?
|
||||
body.value[0].type : body.type);
|
||||
if (/^(bin|rel)$/.test(atomType)) {
|
||||
mclass = "m" + atomType;
|
||||
}
|
||||
return new ParseNode("mclass", {
|
||||
type: "mclass",
|
||||
mclass,
|
||||
value: [
|
||||
new ParseNode("font", {
|
||||
type: "font",
|
||||
font: "boldsymbol",
|
||||
body,
|
||||
}, parser.mode),
|
||||
],
|
||||
}, parser.mode);
|
||||
},
|
||||
});
|
||||
|
||||
const oldFontFuncsMap = {
|
||||
"\\rm": "mathrm",
|
||||
"\\sf": "mathsf",
|
||||
|
@@ -57,12 +57,8 @@ defineFunction({
|
||||
// LaTeX applies \binrel spacing to \overset and \underset. \binrel
|
||||
// spacing varies with (bin|rel|ord) of the atom in the argument.
|
||||
// We'll do the same.
|
||||
let atomType = "";
|
||||
if (baseArg.type === "ordgroup") {
|
||||
atomType = baseArg.value[0].type;
|
||||
} else {
|
||||
atomType = baseArg.type;
|
||||
}
|
||||
const atomType = (baseArg.type === "ordgroup" &&
|
||||
baseArg.value.length ? baseArg.value[0].type : baseArg.type);
|
||||
if (/^(bin|rel)$/.test(atomType)) {
|
||||
mclass = "m" + atomType;
|
||||
} else {
|
||||
|
430
test/__snapshots__/katex-spec.js.snap
Normal file → Executable file
430
test/__snapshots__/katex-spec.js.snap
Normal file → Executable file
@@ -147,6 +147,436 @@ exports[`A begin/end parser should grab \\arraystretch 1`] = `
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`A font parser \\boldsymbol should inherit mbin/mrel from argument 1`] = `
|
||||
[
|
||||
{
|
||||
"classes": [
|
||||
"mord",
|
||||
"mathit"
|
||||
],
|
||||
"depth": 0,
|
||||
"height": 0.43056,
|
||||
"italic": 0,
|
||||
"maxFontSize": 1,
|
||||
"skew": 0,
|
||||
"style": {
|
||||
},
|
||||
"value": "a",
|
||||
"width": 0.52859
|
||||
},
|
||||
{
|
||||
"attributes": {
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"attributes": {
|
||||
},
|
||||
"children": [
|
||||
],
|
||||
"classes": [
|
||||
"mord"
|
||||
],
|
||||
"depth": 0,
|
||||
"height": 0,
|
||||
"maxFontSize": 0,
|
||||
"style": {
|
||||
}
|
||||
}
|
||||
],
|
||||
"classes": [
|
||||
"mord"
|
||||
],
|
||||
"depth": 0,
|
||||
"height": 0,
|
||||
"maxFontSize": 0,
|
||||
"style": {
|
||||
}
|
||||
},
|
||||
{
|
||||
"classes": [
|
||||
"mord",
|
||||
"mathit"
|
||||
],
|
||||
"depth": 0,
|
||||
"height": 0.69444,
|
||||
"italic": 0,
|
||||
"maxFontSize": 1,
|
||||
"skew": 0,
|
||||
"style": {
|
||||
},
|
||||
"value": "b",
|
||||
"width": 0.42917
|
||||
},
|
||||
{
|
||||
"attributes": {
|
||||
},
|
||||
"children": [
|
||||
],
|
||||
"classes": [
|
||||
"mspace"
|
||||
],
|
||||
"depth": 0,
|
||||
"height": 0,
|
||||
"maxFontSize": 0,
|
||||
"style": {
|
||||
"marginRight": "0.2777777777777778em"
|
||||
}
|
||||
},
|
||||
{
|
||||
"attributes": {
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"attributes": {
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"classes": [
|
||||
"mrel",
|
||||
"mathbf"
|
||||
],
|
||||
"depth": -0.10889,
|
||||
"height": 0.39111,
|
||||
"italic": 0,
|
||||
"maxFontSize": 1,
|
||||
"skew": 0,
|
||||
"style": {
|
||||
},
|
||||
"value": "=",
|
||||
"width": 0.89444
|
||||
}
|
||||
],
|
||||
"classes": [
|
||||
"mord"
|
||||
],
|
||||
"depth": 0,
|
||||
"height": 0.39111,
|
||||
"maxFontSize": 1,
|
||||
"style": {
|
||||
}
|
||||
}
|
||||
],
|
||||
"classes": [
|
||||
"mrel"
|
||||
],
|
||||
"depth": 0,
|
||||
"height": 0.39111,
|
||||
"maxFontSize": 1,
|
||||
"style": {
|
||||
}
|
||||
},
|
||||
{
|
||||
"attributes": {
|
||||
},
|
||||
"children": [
|
||||
],
|
||||
"classes": [
|
||||
"mspace"
|
||||
],
|
||||
"depth": 0,
|
||||
"height": 0,
|
||||
"maxFontSize": 0,
|
||||
"style": {
|
||||
"marginRight": "0.2777777777777778em"
|
||||
}
|
||||
},
|
||||
{
|
||||
"classes": [
|
||||
"mord",
|
||||
"mathit"
|
||||
],
|
||||
"depth": 0,
|
||||
"height": 0.43056,
|
||||
"italic": 0,
|
||||
"maxFontSize": 1,
|
||||
"skew": 0.05556,
|
||||
"style": {
|
||||
},
|
||||
"value": "c",
|
||||
"width": 0.43276
|
||||
},
|
||||
{
|
||||
"attributes": {
|
||||
},
|
||||
"children": [
|
||||
],
|
||||
"classes": [
|
||||
"mspace"
|
||||
],
|
||||
"depth": 0,
|
||||
"height": 0,
|
||||
"maxFontSize": 0,
|
||||
"style": {
|
||||
"marginRight": "0.2222222222222222em"
|
||||
}
|
||||
},
|
||||
{
|
||||
"attributes": {
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"attributes": {
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"classes": [
|
||||
"mord",
|
||||
"mathbf"
|
||||
],
|
||||
"depth": 0.13333,
|
||||
"height": 0.63333,
|
||||
"italic": 0,
|
||||
"maxFontSize": 1,
|
||||
"skew": 0,
|
||||
"style": {
|
||||
},
|
||||
"value": "+",
|
||||
"width": 0.89444
|
||||
}
|
||||
],
|
||||
"classes": [
|
||||
"mord"
|
||||
],
|
||||
"depth": 0.13333,
|
||||
"height": 0.63333,
|
||||
"maxFontSize": 1,
|
||||
"style": {
|
||||
}
|
||||
}
|
||||
],
|
||||
"classes": [
|
||||
"mbin"
|
||||
],
|
||||
"depth": 0.13333,
|
||||
"height": 0.63333,
|
||||
"maxFontSize": 1,
|
||||
"style": {
|
||||
}
|
||||
},
|
||||
{
|
||||
"attributes": {
|
||||
},
|
||||
"children": [
|
||||
],
|
||||
"classes": [
|
||||
"mspace"
|
||||
],
|
||||
"depth": 0,
|
||||
"height": 0,
|
||||
"maxFontSize": 0,
|
||||
"style": {
|
||||
"marginRight": "0.2222222222222222em"
|
||||
}
|
||||
},
|
||||
{
|
||||
"classes": [
|
||||
"mord",
|
||||
"mathit"
|
||||
],
|
||||
"depth": 0,
|
||||
"height": 0.69444,
|
||||
"italic": 0,
|
||||
"maxFontSize": 1,
|
||||
"skew": 0.16667,
|
||||
"style": {
|
||||
},
|
||||
"value": "d",
|
||||
"width": 0.52049
|
||||
},
|
||||
{
|
||||
"attributes": {
|
||||
},
|
||||
"children": [
|
||||
],
|
||||
"classes": [
|
||||
"mspace"
|
||||
],
|
||||
"depth": 0,
|
||||
"height": 0,
|
||||
"maxFontSize": 0,
|
||||
"style": {
|
||||
"marginRight": "0.2222222222222222em"
|
||||
}
|
||||
},
|
||||
{
|
||||
"attributes": {
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"attributes": {
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"classes": [
|
||||
"mord",
|
||||
"mathbf"
|
||||
],
|
||||
"depth": 0.13333,
|
||||
"height": 0.63333,
|
||||
"italic": 0,
|
||||
"maxFontSize": 1,
|
||||
"skew": 0,
|
||||
"style": {
|
||||
},
|
||||
"value": "+",
|
||||
"width": 0.89444
|
||||
},
|
||||
{
|
||||
"classes": [
|
||||
"mord",
|
||||
"mathbf"
|
||||
],
|
||||
"depth": 0.13333,
|
||||
"height": 0.63333,
|
||||
"italic": 0,
|
||||
"maxFontSize": 1,
|
||||
"skew": 0,
|
||||
"style": {
|
||||
},
|
||||
"value": "+",
|
||||
"width": 0.89444
|
||||
}
|
||||
],
|
||||
"classes": [
|
||||
"mord"
|
||||
],
|
||||
"depth": 0.13333,
|
||||
"height": 0.63333,
|
||||
"maxFontSize": 1,
|
||||
"style": {
|
||||
}
|
||||
}
|
||||
],
|
||||
"classes": [
|
||||
"mbin"
|
||||
],
|
||||
"depth": 0.13333,
|
||||
"height": 0.63333,
|
||||
"maxFontSize": 1,
|
||||
"style": {
|
||||
}
|
||||
},
|
||||
{
|
||||
"attributes": {
|
||||
},
|
||||
"children": [
|
||||
],
|
||||
"classes": [
|
||||
"mspace"
|
||||
],
|
||||
"depth": 0,
|
||||
"height": 0,
|
||||
"maxFontSize": 0,
|
||||
"style": {
|
||||
"marginRight": "0.2222222222222222em"
|
||||
}
|
||||
},
|
||||
{
|
||||
"classes": [
|
||||
"mord",
|
||||
"mathit"
|
||||
],
|
||||
"depth": 0,
|
||||
"height": 0.43056,
|
||||
"italic": 0,
|
||||
"maxFontSize": 1,
|
||||
"skew": 0.05556,
|
||||
"style": {
|
||||
},
|
||||
"value": "e",
|
||||
"width": 0.46563
|
||||
},
|
||||
{
|
||||
"attributes": {
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"attributes": {
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"classes": [
|
||||
"mord",
|
||||
"boldsymbol"
|
||||
],
|
||||
"depth": 0,
|
||||
"height": 0.44444,
|
||||
"italic": 0,
|
||||
"maxFontSize": 1,
|
||||
"skew": 0,
|
||||
"style": {
|
||||
},
|
||||
"value": "x",
|
||||
"width": 0.65903
|
||||
},
|
||||
{
|
||||
"classes": [
|
||||
"mord",
|
||||
"boldsymbol"
|
||||
],
|
||||
"depth": 0.19444,
|
||||
"height": 0.44444,
|
||||
"italic": 0.03704,
|
||||
"maxFontSize": 1,
|
||||
"skew": 0,
|
||||
"style": {
|
||||
},
|
||||
"value": "y",
|
||||
"width": 0.59028
|
||||
},
|
||||
{
|
||||
"classes": [
|
||||
"mord",
|
||||
"boldsymbol"
|
||||
],
|
||||
"depth": 0,
|
||||
"height": 0.44444,
|
||||
"italic": 0.04213,
|
||||
"maxFontSize": 1,
|
||||
"skew": 0,
|
||||
"style": {
|
||||
},
|
||||
"value": "z",
|
||||
"width": 0.55509
|
||||
}
|
||||
],
|
||||
"classes": [
|
||||
"mord"
|
||||
],
|
||||
"depth": 0.19444,
|
||||
"height": 0.44444,
|
||||
"maxFontSize": 1,
|
||||
"style": {
|
||||
}
|
||||
}
|
||||
],
|
||||
"classes": [
|
||||
"mord"
|
||||
],
|
||||
"depth": 0.19444,
|
||||
"height": 0.44444,
|
||||
"maxFontSize": 1,
|
||||
"style": {
|
||||
}
|
||||
},
|
||||
{
|
||||
"classes": [
|
||||
"mord",
|
||||
"mathit"
|
||||
],
|
||||
"depth": 0.19444,
|
||||
"height": 0.69444,
|
||||
"italic": 0.10764,
|
||||
"maxFontSize": 1,
|
||||
"skew": 0.16667,
|
||||
"style": {
|
||||
},
|
||||
"value": "f",
|
||||
"width": 0.48959
|
||||
}
|
||||
]
|
||||
`;
|
||||
|
||||
exports[`A parser that does not throw on unsupported commands should build katex-error span for other type of KaTeX error 1`] = `
|
||||
{
|
||||
"attributes": {
|
||||
|
@@ -382,30 +382,34 @@ exports[`A MathML builder should render boldsymbol with the correct mathvariants
|
||||
<math>
|
||||
<semantics>
|
||||
<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>
|
||||
<mstyle>
|
||||
<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>
|
||||
</mstyle>
|
||||
</mrow>
|
||||
<annotation encoding="application/x-tex">
|
||||
\\boldsymbol{Ax2k\\omega\\Omega\\imath+}
|
||||
|
@@ -1459,6 +1459,12 @@ describe("A font parser", function() {
|
||||
it("should have the correct greediness", function() {
|
||||
expect("e^\\mathbf{x}").toParse();
|
||||
});
|
||||
|
||||
it("\\boldsymbol should inherit mbin/mrel from argument", () => {
|
||||
const built = _getBuilt("a\\boldsymbol{}b\\boldsymbol{=}c" +
|
||||
"\\boldsymbol{+}d\\boldsymbol{++}e\\boldsymbol{xyz}f");
|
||||
expect(built).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("A comment parser", function() {
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 16 KiB |
Binary file not shown.
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 14 KiB |
@@ -62,7 +62,9 @@ BinCancellation: |
|
||||
\end{array}
|
||||
BinomTest: \dbinom{a}{b}\tbinom{a}{b}^{\binom{a}{b}+17}
|
||||
BoldSpacing: \mathbf{A}^2+\mathbf{B}_3*\mathscr{C}'
|
||||
BoldSymbol: \sum_{\boldsymbol{\alpha}}^{\boldsymbol{\beta}} \boldsymbol{\omega}+ \int_{\boldsymbol{\alpha}}^{\boldsymbol{\beta}} \boldsymbol{\Omega}+\boldsymbol{Ax2k\omega\Omega\imath+}
|
||||
BoldSymbol: |
|
||||
\sum_{\boldsymbol{\alpha}}^{\boldsymbol{\beta}} \boldsymbol{\omega}+ \int_{\boldsymbol{\alpha}}^{\boldsymbol{\beta}} \boldsymbol{\Omega}+\boldsymbol{Ax2k\omega\Omega\imath+} \\
|
||||
x \boldsymbol{+} y \boldsymbol{=} z
|
||||
Boxed: \boxed{F=ma} \quad \boxed{ac}\color{magenta}{\boxed{F}}\boxed{F=mg}
|
||||
Cases: |
|
||||
f(a,b)=\begin{cases}
|
||||
|
Reference in New Issue
Block a user