mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-06 11:48:41 +00:00
\@binrel command and refactor (#1487)
* \@binrel command and refactor New `\@binrel{x}{y}` command renders `y` as if it's a bin/rel/ord like `x`. This is equivalent to AMSTeX's `\binrel@{x}\binrel@@{y}`. It will hopefully be useful for macros, such as `\pmb` (#1418). Also refactor the (already duplicated) code for implementing this functionality into buildCommon.binrelClass. * Add tests; fix flow error * Another test * Move binrelClass to functions/mclass.js * Remove expensive array destructuring polyfill
This commit is contained in:
committed by
Kevin Barabash
parent
8f5239c272
commit
578877764d
@@ -1,6 +1,7 @@
|
||||
// @flow
|
||||
// TODO(kevinb): implement \\sl and \\sc
|
||||
|
||||
import {binrelClass} from "./mclass";
|
||||
import defineFunction from "../defineFunction";
|
||||
import ParseNode from "../ParseNode";
|
||||
|
||||
@@ -69,17 +70,11 @@ defineFunction({
|
||||
},
|
||||
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;
|
||||
}
|
||||
// amsbsy.sty's \boldsymbol uses \binrel spacing to inherit the
|
||||
// argument's bin|rel|ord status
|
||||
return new ParseNode("mclass", {
|
||||
type: "mclass",
|
||||
mclass,
|
||||
mclass: binrelClass(body),
|
||||
value: [
|
||||
new ParseNode("font", {
|
||||
type: "font",
|
||||
|
@@ -3,6 +3,7 @@ import defineFunction, {ordargument} from "../defineFunction";
|
||||
import buildCommon from "../buildCommon";
|
||||
import mathMLTree from "../mathMLTree";
|
||||
import ParseNode from "../ParseNode";
|
||||
import type {AnyParseNode} from "../ParseNode";
|
||||
|
||||
import * as html from "../buildHTML";
|
||||
import * as mml from "../buildMathML";
|
||||
@@ -41,6 +42,37 @@ defineFunction({
|
||||
mathmlBuilder,
|
||||
});
|
||||
|
||||
export const binrelClass = (arg: AnyParseNode) => {
|
||||
// \binrel@ spacing varies with (bin|rel|ord) of the atom in the argument.
|
||||
// (by rendering separately and with {}s before and after, and measuring
|
||||
// the change in spacing). We'll do roughly the same by detecting the
|
||||
// atom type directly.
|
||||
const atomType = (arg.type === "ordgroup" &&
|
||||
arg.value.length ? arg.value[0].type : arg.type);
|
||||
if (/^(bin|rel)$/.test(atomType)) {
|
||||
return "m" + atomType;
|
||||
} else {
|
||||
return "mord";
|
||||
}
|
||||
};
|
||||
|
||||
// \@binrel{x}{y} renders like y but as mbin/mrel/mord if x is mbin/mrel/mord.
|
||||
// This is equivalent to \binrel@{x}\binrel@@{y} in AMSTeX.
|
||||
defineFunction({
|
||||
type: "mclass",
|
||||
names: ["\\@binrel"],
|
||||
props: {
|
||||
numArgs: 2,
|
||||
},
|
||||
handler({parser}, args) {
|
||||
return new ParseNode("mclass", {
|
||||
type: "mclass",
|
||||
mclass: binrelClass(args[0]),
|
||||
value: [args[1]],
|
||||
}, parser.mode);
|
||||
},
|
||||
});
|
||||
|
||||
// Build a relation or stacked op by placing one symbol on top of another
|
||||
defineFunction({
|
||||
type: "mclass",
|
||||
@@ -52,21 +84,12 @@ defineFunction({
|
||||
const baseArg = args[1];
|
||||
const shiftedArg = args[0];
|
||||
|
||||
let mclass = "mrel"; // default. May change below.
|
||||
let mclass;
|
||||
if (funcName !== "\\stackrel") {
|
||||
// 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.
|
||||
const atomType = (baseArg.type === "ordgroup" &&
|
||||
baseArg.value.length ? baseArg.value[0].type : baseArg.type);
|
||||
if (/^(bin|rel)$/.test(atomType)) {
|
||||
mclass = "m" + atomType;
|
||||
} else {
|
||||
// This may capture some instances in which the baseArg is more
|
||||
// than just a single symbol. Say a \overset inside an \overset.
|
||||
// TODO: A more comprehensive way to determine the baseArg type.
|
||||
mclass = "mord";
|
||||
}
|
||||
// LaTeX applies \binrel spacing to \overset and \underset.
|
||||
mclass = binrelClass(baseArg);
|
||||
} else {
|
||||
mclass = "mrel"; // for \stackrel
|
||||
}
|
||||
|
||||
const baseOp = new ParseNode("op", {
|
||||
|
@@ -2999,6 +2999,23 @@ describe("\\tag support", function() {
|
||||
});
|
||||
});
|
||||
|
||||
describe("\\@binrel automatic bin/rel/ord", () => {
|
||||
it("should generate proper class", () => {
|
||||
expect("L\\@binrel+xR").toParseLike("L\\mathbin xR");
|
||||
expect("L\\@binrel=xR").toParseLike("L\\mathrel xR");
|
||||
expect("L\\@binrel xxR").toParseLike("L\\mathord xR");
|
||||
expect("L\\@binrel{+}{x}R").toParseLike("L\\mathbin{{x}}R");
|
||||
expect("L\\@binrel{=}{x}R").toParseLike("L\\mathrel{{x}}R");
|
||||
expect("L\\@binrel{x}{x}R").toParseLike("L\\mathord{{x}}R");
|
||||
});
|
||||
|
||||
it("should base on just first character in group", () => {
|
||||
expect("L\\@binrel{+x}xR").toParseLike("L\\mathbin xR");
|
||||
expect("L\\@binrel{=x}xR").toParseLike("L\\mathrel xR");
|
||||
expect("L\\@binrel{xx}xR").toParseLike("L\\mathord xR");
|
||||
});
|
||||
});
|
||||
|
||||
describe("A parser taking String objects", function() {
|
||||
it("should not fail on an empty String object", function() {
|
||||
expect(new String("")).toParse();
|
||||
|
Reference in New Issue
Block a user