Repository: Khan/KaTeX
Pull request #1119 (2018-01-31 02:07:21)

extract font functions and implicit color function


Patch:
diff --git a/src/Parser.js b/src/Parser.js
index dc7004f2..0b7fdcf6 100644
--- a/src/Parser.js
+++ b/src/Parser.js
@@ -434,17 +434,6 @@ export default class Parser {
         }
     }
 
-    // Old font functions
-    static oldFontFuncs = {
-        "\\rm": "mathrm",
-        "\\sf": "mathsf",
-        "\\tt": "mathtt",
-        "\\bf": "mathbf",
-        "\\it": "mathit",
-        //"\\sl": "textsl",
-        //"\\sc": "textsc",
-    };
-
     /**
      * Parses an implicit group, which is a group that starts at the end of a
      * specified, and ends right before a higher explicit group ends, or at EOL. It
@@ -515,34 +504,6 @@ export default class Parser {
                     endNameToken);
             }
             return result;
-        } else if (func in Parser.oldFontFuncs) {
-            const style = Parser.oldFontFuncs[func];
-            // If we see an old font function, parse out the implicit body
-            this.consumeSpaces();
-            const body = this.parseExpression(true, breakOnTokenText);
-            if (style.slice(0, 4) === 'text') {
-                return new ParseNode("text", {
-                    style: style,
-                    body: new ParseNode("ordgroup", body, this.mode),
-                }, this.mode);
-            } else {
-                return new ParseNode("font", {
-                    font: style,
-                    body: new ParseNode("ordgroup", body, this.mode),
-                }, this.mode);
-            }
-        } else if (func === "\\color") {
-            // If we see a styling function, parse out the implicit body
-            const color = this.parseColorGroup(false);
-            if (!color) {
-                throw new ParseError("\\color not followed by color");
-            }
-            const body = this.parseExpression(true, breakOnTokenText);
-            return new ParseNode("color", {
-                type: "color",
-                color: color.result.value,
-                value: body,
-            }, this.mode);
         } else {
             // Defer to parseGivenFunction if it's not a function we handle
             return this.parseGivenFunction(start, breakOnTokenText);
diff --git a/src/buildHTML.js b/src/buildHTML.js
index 092b8c55..51aece30 100644
--- a/src/buildHTML.js
+++ b/src/buildHTML.js
@@ -422,11 +422,6 @@ groupTypes.spacing = function(group, options) {
     }
 };
 
-groupTypes.font = function(group, options) {
-    const font = group.value.font;
-    return buildGroup(group.value.body, options.withFontFamily(font));
-};
-
 groupTypes.horizBrace = function(group, options) {
     const style = options.style;
 
diff --git a/src/buildMathML.js b/src/buildMathML.js
index 07b44cfd..ecc19342 100644
--- a/src/buildMathML.js
+++ b/src/buildMathML.js
@@ -242,11 +242,6 @@ groupTypes.spacing = function(group) {
     return node;
 };
 
-groupTypes.font = function(group, options) {
-    const font = group.value.font;
-    return buildGroup(group.value.body, options.withFontFamily(font));
-};
-
 groupTypes.horizBrace = function(group, options) {
     const accentNode = stretchy.mathMLnode(group.value.label);
     return new mathMLTree.MathNode(
diff --git a/src/functions.js b/src/functions.js
index 33023b38..6f2a5988 100644
--- a/src/functions.js
+++ b/src/functions.js
@@ -33,14 +33,6 @@ import "./functions/color";
 
 import "./functions/text";
 
-// \color is handled in Parser.js's parseImplicitGroup
-defineFunction(["\\color"], {
-    numArgs: 1,
-    allowedInText: true,
-    greediness: 3,
-    argTypes: ["color"],
-}, null);
-
 import "./functions/enclose";
 
 import "./functions/overline";
@@ -98,13 +90,6 @@ defineFunction(["\\stackrel"], {
 
 import "./functions/mod";
 
-const fontAliases = {
-    "\\Bbb": "\\mathbb",
-    "\\bold": "\\mathbf",
-    "\\frak": "\\mathfrak",
-    "\\bm": "\\boldsymbol",
-};
-
 const singleCharIntegrals: {[string]: string} = {
     "\u222b": "\\int",
     "\u222c": "\\iint",
@@ -183,36 +168,7 @@ import "./functions/sizing";
 
 import "./functions/styling";
 
-// Old font changing functions
-defineFunction([
-    "\\rm", "\\sf", "\\tt", "\\bf", "\\it", //"\\sl", "\\sc",
-], {numArgs: 0}, null);
-
-defineFunction([
-    // styles
-    "\\mathrm", "\\mathit", "\\mathbf", "\\boldsymbol",
-
-    // families
-    "\\mathbb", "\\mathcal", "\\mathfrak", "\\mathscr", "\\mathsf",
-    "\\mathtt",
-
-    // aliases
-    "\\Bbb", "\\bold", "\\frak", "\\bm",
-], {
-    numArgs: 1,
-    greediness: 2,
-}, function(context, args) {
-    const body = args[0];
-    let func = context.funcName;
-    if (func in fontAliases) {
-        func = fontAliases[func];
-    }
-    return {
-        type: "font",
-        font: func.slice(1),
-        body: body,
-    };
-});
+import "./functions/font";
 
 import "./functions/accent";
 
diff --git a/src/functions/color.js b/src/functions/color.js
index 4c04ce50..9e4715ff 100644
--- a/src/functions/color.js
+++ b/src/functions/color.js
@@ -2,6 +2,7 @@
 import defineFunction, {ordargument} from "../defineFunction";
 import buildCommon from "../buildCommon";
 import mathMLTree from "../mathMLTree";
+import ParseError from "../ParseError";
 
 import * as html from "../buildHTML";
 import * as mml from "../buildMathML";
@@ -86,3 +87,33 @@ defineFunction({
     htmlBuilder,
     mathmlBuilder,
 });
+
+defineFunction({
+    type: "color",
+    names: ["\\color"],
+    props: {
+        numArgs: 1,
+        allowedInText: true,
+        greediness: 3,
+        argTypes: ["color"],
+    },
+    handler(context, args) {
+        const {parser, breakOnTokenText} = context;
+
+        const color = args[0];
+        if (!color) {
+            throw new ParseError("\\color not followed by color");
+        }
+
+        // If we see a styling function, parse out the implicit body
+        const body = parser.parseExpression(true, breakOnTokenText);
+
+        return {
+            type: "color",
+            color: color.value,
+            value: body,
+        };
+    },
+    htmlBuilder,
+    mathmlBuilder,
+});
diff --git a/src/functions/font.js b/src/functions/font.js
new file mode 100644
index 00000000..4ad09dfc
--- /dev/null
+++ b/src/functions/font.js
@@ -0,0 +1,92 @@
+// @flow
+// TODO(kevinb): implement \\sl and \\sc
+
+import defineFunction from "../defineFunction";
+import ParseNode from "../ParseNode";
+
+import * as html from "../buildHTML";
+import * as mml from "../buildMathML";
+
+
+const htmlBuilder = (group, options) => {
+    const font = group.value.font;
+    return html.buildGroup(group.value.body, options.withFontFamily(font));
+};
+
+const mathmlBuilder = (group, options) => {
+    const font = group.value.font;
+    return mml.buildGroup(group.value.body, options.withFontFamily(font));
+};
+
+const fontAliases = {
+    "\\Bbb": "\\mathbb",
+    "\\bold": "\\mathbf",
+    "\\frak": "\\mathfrak",
+    "\\bm": "\\boldsymbol",
+};
+
+defineFunction({
+    type: "font",
+    names: [
+        // styles
+        "\\mathrm", "\\mathit", "\\mathbf", "\\boldsymbol",
+
+        // families
+        "\\mathbb", "\\mathcal", "\\mathfrak", "\\mathscr", "\\mathsf",
+        "\\mathtt",
+
+        // aliases
+        "\\Bbb", "\\bold", "\\frak", "\\bm",
+    ],
+    props: {
+        numArgs: 1,
+        greediness: 2,
+    },
+    handler: (context, args) => {
+        const body = args[0];
+        let func = context.funcName;
+        if (func in fontAliases) {
+            func = fontAliases[func];
+        }
+        return {
+            type: "font",
+            font: func.slice(1),
+            body: body,
+        };
+    },
+    htmlBuilder,
+    mathmlBuilder,
+});
+
+const oldFontFuncsMap = {
+    "\\rm": "mathrm",
+    "\\sf": "mathsf",
+    "\\tt": "mathtt",
+    "\\bf": "mathbf",
+    "\\it": "mathit",
+};
+
+// Old font changing functions
+defineFunction({
+    type: "font",
+    names: Object.keys(oldFontFuncsMap),
+    props: {
+        numArgs: 0,
+        allowedInText: true,
+    },
+    handler: (context, args) => {
+        const {parser, funcName, breakOnTokenText} = context;
+
+        parser.consumeSpaces();
+        const body = parser.parseExpression(true, breakOnTokenText);
+        const style = oldFontFuncsMap[funcName];
+
+        return {
+            type: "font",
+            font: style,
+            body: new ParseNode("ordgroup", body, parser.mode),
+        };
+    },
+    htmlBuilder,
+    mathmlBuilder,
+});


Test patch:
diff --git a/test/__snapshots__/katex-spec.js.snap b/test/__snapshots__/katex-spec.js.snap
index 7d1324c1..c46a8131 100644
--- a/test/__snapshots__/katex-spec.js.snap
+++ b/test/__snapshots__/katex-spec.js.snap
@@ -158,6 +158,7 @@ exports[`An implicit group parser within optional groups should work wwith old f
             "type": "font",
             "mode": "math",
             "value": {
+              "type": "font",
               "body": {
                 "type": "ordgroup",
                 "mode": "math",