From 7723d3dcaf3604040b91ed3805de09cb96a9942c Mon Sep 17 00:00:00 2001 From: Emily Eisenberg Date: Wed, 26 Mar 2014 22:17:41 -0400 Subject: [PATCH] First attempt at `\text` function Summary: Make all of the parsing functions keep track of whether they are parsing in math mode or text mode. Then, add a separate lexing function to lex text mode, which is different than the normal mode because it does weird things with spacing and allows a different set of characters. Test Plan: - See that the normal tests work - See that the huxley screenshot looks reasonable - See that none of the other huxley screenshots changed Reviewers: alpert Reviewed By: alpert Differential Revision: http://phabricator.khanacademy.org/D7578 --- Lexer.js | 34 +- Parser.js | 117 ++- buildTree.js | 82 +- symbols.js | 1123 ++++++++++++----------- test/huxley/Huxleyfile | 5 +- test/huxley/Text.huxley/record.json | 1 + test/huxley/Text.huxley/screenshot0.png | Bin 0 -> 12747 bytes test/katex-tests.js | 49 + 8 files changed, 785 insertions(+), 626 deletions(-) create mode 100644 test/huxley/Text.huxley/record.json create mode 100644 test/huxley/Text.huxley/screenshot0.png diff --git a/Lexer.js b/Lexer.js index e06171d98..37ec056c7 100644 --- a/Lexer.js +++ b/Lexer.js @@ -13,7 +13,7 @@ function LexResult(type, text, position) { } // "normal" types of tokens -var normals = [ +var mathNormals = [ [/^[/|@."`0-9]/, "textord"], [/^[a-zA-Z]/, "mathord"], [/^[*+-]/, "bin"], @@ -28,17 +28,30 @@ var normals = [ [/^[)\]?!]/, "close"] ]; +var textNormals = [ + [/^[a-zA-Z0-9`!@*()-=+\[\]'";:?\/.,]/, "textord"], + [/^{/, "{"], + [/^}/, "}"] +]; + // Build a regex to easily parse the functions var anyFunc = /^\\(?:[a-zA-Z]+|.)/; -// Lex a single token -Lexer.prototype.lex = function(pos) { +Lexer.prototype._innerLex = function(pos, normals, ignoreWhitespace) { var input = this._input.slice(pos); // Get rid of whitespace - var whitespace = input.match(/^\s*/)[0]; - pos += whitespace.length; - input = input.slice(whitespace.length); + if (ignoreWhitespace) { + var whitespace = input.match(/^\s*/)[0]; + pos += whitespace.length; + input = input.slice(whitespace.length); + } else { + // Do the funky concatenation of whitespace + var whitespace = input.match(/^( +|\\ +)/); + if (whitespace !== null) { + return new LexResult(" ", " ", pos + whitespace[0].length); + } + } // If there's no more input to parse, return an EOF token if (input.length === 0) { @@ -66,6 +79,15 @@ Lexer.prototype.lex = function(pos) { // We didn't match any of the tokens, so throw an error. throw new ParseError("Unexpected character: '" + input[0] + "' at position " + pos); +} + +// Lex a single token +Lexer.prototype.lex = function(pos, mode) { + if (mode === "math") { + return this._innerLex(pos, mathNormals, true); + } else if (mode === "text") { + return this._innerLex(pos, textNormals, false); + } }; module.exports = Lexer; diff --git a/Parser.js b/Parser.js index 28eb38658..0db2e1458 100644 --- a/Parser.js +++ b/Parser.js @@ -16,9 +16,10 @@ function ParseResult(result, newPosition) { } // The resulting parse tree nodes of the parse tree. -function ParseNode(type, value) { +function ParseNode(type, value, mode) { this.type = type; this.value = value; + this.mode = mode; } // Checks a result to make sure it has the right type, and throws an @@ -37,27 +38,27 @@ Parser.prototype.parse = function(input) { this.lexer = new Lexer(input); // Try to parse the input - var parse = this.parseInput(0); + var parse = this.parseInput(0, "math"); return parse.result; }; // Parses an entire input tree -Parser.prototype.parseInput = function(pos) { +Parser.prototype.parseInput = function(pos, mode) { // Parse an expression - var expression = this.parseExpression(pos); + var expression = this.parseExpression(pos, mode); // If we succeeded, make sure there's an EOF at the end - var EOF = this.lexer.lex(expression.position); + var EOF = this.lexer.lex(expression.position, mode); expect(EOF, "EOF"); return expression; }; // Parses an "expression", which is a list of atoms -Parser.prototype.parseExpression = function(pos) { +Parser.prototype.parseExpression = function(pos, mode) { // Start with a list of nodes var expression = []; while (true) { // Try to parse atoms - var parse = this.parseAtom(pos); + var parse = this.parseAtom(pos, mode); if (parse) { // Copy them into the list expression.push(parse.result); @@ -70,12 +71,16 @@ Parser.prototype.parseExpression = function(pos) { }; // Parses a superscript expression, like "^3" -Parser.prototype.parseSuperscript = function(pos) { +Parser.prototype.parseSuperscript = function(pos, mode) { + if (mode !== "math") { + throw new ParseError("Trying to parse superscript in non-math mode"); + } + // Try to parse a "^" character - var sup = this.lexer.lex(pos); + var sup = this.lexer.lex(pos, mode); if (sup.type === "^") { // If we got one, parse the corresponding group - var group = this.parseGroup(sup.position); + var group = this.parseGroup(sup.position, mode); if (group) { return group; } else { @@ -85,19 +90,23 @@ Parser.prototype.parseSuperscript = function(pos) { } else if (sup.type === "'") { var pos = sup.position; return new ParseResult( - new ParseNode("textord", "\\prime"), sup.position); + new ParseNode("textord", "\\prime"), sup.position, mode); } else { return null; } }; // Parses a subscript expression, like "_3" -Parser.prototype.parseSubscript = function(pos) { +Parser.prototype.parseSubscript = function(pos, mode) { + if (mode !== "math") { + throw new ParseError("Trying to parse subscript in non-math mode"); + } + // Try to parse a "_" character - var sub = this.lexer.lex(pos); + var sub = this.lexer.lex(pos, mode); if (sub.type === "_") { // If we got one, parse the corresponding group - var group = this.parseGroup(sub.position); + var group = this.parseGroup(sub.position, mode); if (group) { return group; } else { @@ -111,12 +120,18 @@ Parser.prototype.parseSubscript = function(pos) { // Parses an atom, which consists of a nucleus, and an optional superscript and // subscript -Parser.prototype.parseAtom = function(pos) { +Parser.prototype.parseAtom = function(pos, mode) { // Parse the nucleus - var nucleus = this.parseGroup(pos); + var nucleus = this.parseGroup(pos, mode); var nextPos = pos; var nucleusNode; + // Text mode doesn't have superscripts or subscripts, so we only parse the + // nucleus in this case + if (mode === "text") { + return nucleus; + } + if (nucleus) { nextPos = nucleus.position; nucleusNode = nucleus.result; @@ -129,7 +144,7 @@ Parser.prototype.parseAtom = function(pos) { // depending on whether those succeed, we return the correct type. while (true) { var node; - if ((node = this.parseSuperscript(nextPos))) { + if ((node = this.parseSuperscript(nextPos, mode))) { if (sup) { throw new ParseError("Parse error: Double superscript"); } @@ -137,7 +152,7 @@ Parser.prototype.parseAtom = function(pos) { sup = node.result; continue; } - if ((node = this.parseSubscript(nextPos))) { + if ((node = this.parseSubscript(nextPos, mode))) { if (sub) { throw new ParseError("Parse error: Double subscript"); } @@ -151,7 +166,7 @@ Parser.prototype.parseAtom = function(pos) { if (sup || sub) { return new ParseResult( new ParseNode("supsub", {base: nucleusNode, sup: sup, - sub: sub}), + sub: sub}, mode), nextPos); } else { return nucleus; @@ -160,25 +175,24 @@ Parser.prototype.parseAtom = function(pos) { // Parses a group, which is either a single nucleus (like "x") or an expression // in braces (like "{x+y}") -Parser.prototype.parseGroup = function(pos) { - var start = this.lexer.lex(pos); +Parser.prototype.parseGroup = function(pos, mode) { + var start = this.lexer.lex(pos, mode); // Try to parse an open brace if (start.type === "{") { // If we get a brace, parse an expression - var expression = this.parseExpression(start.position); + var expression = this.parseExpression(start.position, mode); // Make sure we get a close brace - var closeBrace = this.lexer.lex(expression.position); + var closeBrace = this.lexer.lex(expression.position, mode); expect(closeBrace, "}"); return new ParseResult( - new ParseNode("ordgroup", expression.result), + new ParseNode("ordgroup", expression.result, mode), closeBrace.position); } else { // Otherwise, just return a nucleus - return this.parseNucleus(pos); + return this.parseNucleus(pos, mode); } }; - // A list of 1-argument color functions var colorFuncs = [ "\\blue", "\\orange", "\\pink", "\\red", "\\green", "\\gray", "\\purple" @@ -200,12 +214,12 @@ var namedFns = [ // Parses a "nucleus", which is either a single token from the tokenizer or a // function and its arguments -Parser.prototype.parseNucleus = function(pos) { - var nucleus = this.lexer.lex(pos); +Parser.prototype.parseNucleus = function(pos, mode) { + var nucleus = this.lexer.lex(pos, mode); if (utils.contains(colorFuncs, nucleus.type)) { // If this is a color function, parse its argument and return - var group = this.parseGroup(nucleus.position); + var group = this.parseGroup(nucleus.position, mode); if (group) { var atoms; if (group.result.type === "ordgroup") { @@ -215,55 +229,66 @@ Parser.prototype.parseNucleus = function(pos) { } return new ParseResult( new ParseNode("color", - {color: nucleus.type.slice(1), value: atoms}), + {color: nucleus.type.slice(1), value: atoms}, mode), group.position); } else { throw new ParseError( "Expected group after '" + nucleus.text + "'"); } - } else if (utils.contains(sizeFuncs, nucleus.type)) { + } else if (mode === "math" && utils.contains(sizeFuncs, nucleus.type)) { // If this is a size function, parse its argument and return - var group = this.parseGroup(nucleus.position); + var group = this.parseGroup(nucleus.position, mode); if (group) { return new ParseResult( new ParseNode("sizing", { size: "size" + (utils.indexOf(sizeFuncs, nucleus.type) + 1), value: group.result - }), + }, mode), group.position); } else { throw new ParseError( "Expected group after '" + nucleus.text + "'"); } - } else if (utils.contains(namedFns, nucleus.type)) { + } else if (mode === "math" && utils.contains(namedFns, nucleus.type)) { // If this is a named function, just return it plain return new ParseResult( - new ParseNode("namedfn", nucleus.text), + new ParseNode("namedfn", nucleus.text, mode), nucleus.position); } else if (nucleus.type === "\\llap" || nucleus.type === "\\rlap") { // If this is an llap or rlap, parse its argument and return - var group = this.parseGroup(nucleus.position); + var group = this.parseGroup(nucleus.position, mode); if (group) { return new ParseResult( - new ParseNode(nucleus.type.slice(1), group.result), + new ParseNode(nucleus.type.slice(1), group.result, mode), group.position); } else { throw new ParseError( "Expected group after '" + nucleus.text + "'"); } - } else if (nucleus.type === "\\dfrac" || nucleus.type === "\\frac" || - nucleus.type === "\\tfrac") { + } else if (mode === "math" && nucleus.type === "\\text") { + var group = this.parseGroup(nucleus.position, "text"); + if (group) { + return new ParseResult( + new ParseNode(nucleus.type.slice(1), group.result, mode), + group.position); + } else { + throw new ParseError( + "Expected group after '" + nucleus.text + "'"); + } + } else if (mode === "math" && (nucleus.type === "\\dfrac" || + nucleus.type === "\\frac" || + nucleus.type === "\\tfrac")) { // If this is a frac, parse its two arguments and return - var numer = this.parseGroup(nucleus.position); + var numer = this.parseGroup(nucleus.position, mode); if (numer) { - var denom = this.parseGroup(numer.position); + var denom = this.parseGroup(numer.position, mode); if (denom) { return new ParseResult( new ParseNode("frac", { numer: numer.result, denom: denom.result, size: nucleus.type.slice(1) - }), + }, mode), denom.position); } else { throw new ParseError("Expected denominator after '" + @@ -273,17 +298,17 @@ Parser.prototype.parseNucleus = function(pos) { throw new ParseError("Parse error: Expected numerator after '" + nucleus.type + "'"); } - } else if (nucleus.type === "\\KaTeX") { + } else if (mode === "math" && nucleus.type === "\\KaTeX") { // If this is a KaTeX node, return the special katex result return new ParseResult( - new ParseNode("katex", null), + new ParseNode("katex", null, mode), nucleus.position ); - } else if (symbols[nucleus.text]) { + } else if (symbols[mode][nucleus.text]) { // Otherwise if this is a no-argument function, find the type it // corresponds to in the symbols map return new ParseResult( - new ParseNode(symbols[nucleus.text].group, nucleus.text), + new ParseNode(symbols[mode][nucleus.text].group, nucleus.text, mode), nucleus.position); } else { // Otherwise, we couldn't parse it diff --git a/buildTree.js b/buildTree.js index 4bb0608b4..9c6e9ad3e 100644 --- a/buildTree.js +++ b/buildTree.js @@ -50,6 +50,7 @@ var groupToType = { ordgroup: "mord", namedfn: "mop", katex: "mord", + text: "mord", }; var getTypeOfGroup = function(group) { @@ -69,11 +70,17 @@ var getTypeOfGroup = function(group) { var groupTypes = { mathord: function(group, options, prev) { - return makeSpan(["mord", options.color], [mathit(group.value)]); + return makeSpan( + ["mord", options.color], + [mathit(group.value, group.mode)] + ); }, textord: function(group, options, prev) { - return makeSpan(["mord", options.color], [mathrm(group.value)]); + return makeSpan( + ["mord", options.color], + [mathrm(group.value, group.mode)] + ); }, bin: function(group, options, prev) { @@ -88,15 +95,23 @@ var groupTypes = { group.type = "ord"; className = "mord"; } - return makeSpan([className, options.color], [mathrm(group.value)]); + return makeSpan( + [className, options.color], + [mathrm(group.value, group.mode)] + ); }, rel: function(group, options, prev) { - return makeSpan(["mrel", options.color], [mathrm(group.value)]); + return makeSpan( + ["mrel", options.color], + [mathrm(group.value, group.mode)] + ); }, - amsrel: function(group, options, prev) { - return makeSpan(["mrel", options.color], [amsrm(group.value)]); + text: function(group, options, prev) { + return makeSpan(["text mord", options.style.cls()], + [buildGroup(group.value, options.reset())] + ); }, supsub: function(group, options, prev) { @@ -185,11 +200,17 @@ var groupTypes = { }, open: function(group, options, prev) { - return makeSpan(["mopen", options.color], [mathrm(group.value)]); + return makeSpan( + ["mopen", options.color], + [mathrm(group.value, group.mode)] + ); }, close: function(group, options, prev) { - return makeSpan(["mclose", options.color], [mathrm(group.value)]); + return makeSpan( + ["mclose", options.color], + [mathrm(group.value, group.mode)] + ); }, frac: function(group, options, prev) { @@ -283,8 +304,14 @@ var groupTypes = { }, spacing: function(group, options, prev) { - if (group.value === "\\ " || group.value === "\\space") { - return makeSpan(["mord", "mspace"], [mathrm(group.value)]); + if (group.value === "\\ " || group.value === "\\space" || + group.value === " ") { + return makeSpan( + ["mord", "mspace"], + [mathrm(group.value, group.mode)] + ); + } else if(group.value === "~") { + return makeSpan(["mord", "mspace"], [mathrm(" ", group.mode)]); } else { var spacingClassMap = { "\\qquad": "qquad", @@ -311,7 +338,10 @@ var groupTypes = { }, punct: function(group, options, prev) { - return makeSpan(["mpunct", options.color], [mathrm(group.value)]); + return makeSpan( + ["mpunct", options.color], + [mathrm(group.value, group.mode)] + ); }, ordgroup: function(group, options, prev) { @@ -323,26 +353,26 @@ var groupTypes = { namedfn: function(group, options, prev) { var chars = []; for (var i = 1; i < group.value.length; i++) { - chars.push(mathrm(group.value[i])); + chars.push(mathrm(group.value[i], group.mode)); } return makeSpan(["mop", options.color], chars); }, katex: function(group, options, prev) { - var k = makeSpan(["k"], [mathrm("K")]); - var a = makeSpan(["a"], [mathrm("A")]); + var k = makeSpan(["k"], [mathrm("K", group.mode)]); + var a = makeSpan(["a"], [mathrm("A", group.mode)]); a.height = (a.height + 0.2) * 0.75; a.depth = (a.height - 0.2) * 0.75; - var t = makeSpan(["t"], [mathrm("T")]); - var e = makeSpan(["e"], [mathrm("E")]); + var t = makeSpan(["t"], [mathrm("T", group.mode)]); + var e = makeSpan(["e"], [mathrm("E", group.mode)]); e.height = (e.height - 0.2155); e.depth = (e.depth + 0.2155); - var x = makeSpan(["x"], [mathrm("X")]); + var x = makeSpan(["x"], [mathrm("X", group.mode)]); return makeSpan(["katex-logo", options.color], [k, a, t, e, x]); }, @@ -407,9 +437,9 @@ var buildGroup = function(group, options, prev) { } }; -var makeText = function(value, style) { - if (symbols[value].replace) { - value = symbols[value].replace; +var makeText = function(value, style, mode) { + if (symbols[mode][value].replace) { + value = symbols[mode][value].replace; } var metrics = fontMetrics.getCharacterMetrics(value, style); @@ -432,15 +462,15 @@ var makeText = function(value, style) { } }; -var mathit = function(value) { - return makeSpan(["mathit"], [makeText(value, "math-italic")]); +var mathit = function(value, mode) { + return makeSpan(["mathit"], [makeText(value, "math-italic", mode)]); }; -var mathrm = function(value) { - if (symbols[value].font === "main") { - return makeText(value, "main-regular"); +var mathrm = function(value, mode) { + if (symbols[mode][value].font === "main") { + return makeText(value, "main-regular", mode); } else { - return makeSpan(["amsrm"], [makeText(value, "ams-regular")]); + return makeSpan(["amsrm"], [makeText(value, "ams-regular", mode)]); } }; diff --git a/symbols.js b/symbols.js index 0f0d28d1c..d4294f325 100644 --- a/symbols.js +++ b/symbols.js @@ -8,567 +8,596 @@ * - replace (optiona): the character that this symbol or function should be * replaced with (i.e. "\phi" has a replace value of "\u03d5", the phi * character in the main font) + * There outermost map in the table indicates what mode the symbols should be + * accepted in (e.g. "math" or "text") */ var symbols = { - "`": { - font: "main", - group: "textord", - replace: "\u2018" - }, - "\\$": { - font: "main", - group: "textord", - replace: "$" - }, - "\\%": { - font: "main", - group: "textord", - replace: "%" - }, - "\\angle": { - font: "main", - group: "textord", - replace: "\u2220" - }, - "\\infty": { - font: "main", - group: "textord", - replace: "\u221e" - }, - "\\prime": { - font: "main", - group: "textord", - replace: "\u2032" - }, - "\\triangle": { - font: "main", - group: "textord", - replace: "\u25b3" - }, - "\\Gamma": { - font: "main", - group: "textord", - replace: "\u0393" - }, - "\\Delta": { - font: "main", - group: "textord", - replace: "\u0394" - }, - "\\Theta": { - font: "main", - group: "textord", - replace: "\u0398" - }, - "\\Lambda": { - font: "main", - group: "textord", - replace: "\u039b" - }, - "\\Xi": { - font: "main", - group: "textord", - replace: "\u039e" - }, - "\\Pi": { - font: "main", - group: "textord", - replace: "\u03a0" - }, - "\\Sigma": { - font: "main", - group: "textord", - replace: "\u03a3" - }, - "\\Upsilon": { - font: "main", - group: "textord", - replace: "\u03a5" - }, - "\\Phi": { - font: "main", - group: "textord", - replace: "\u03a6" - }, - "\\Psi": { - font: "main", - group: "textord", - replace: "\u03a8" - }, - "\\Omega": { - font: "main", - group: "textord", - replace: "\u03a9" - }, - "\\alpha": { - font: "main", - group: "mathord", - replace: "\u03b1" - }, - "\\beta": { - font: "main", - group: "mathord", - replace: "\u03b2" - }, - "\\gamma": { - font: "main", - group: "mathord", - replace: "\u03b3" - }, - "\\delta": { - font: "main", - group: "mathord", - replace: "\u03b4" - }, - "\\epsilon": { - font: "main", - group: "mathord", - replace: "\u03f5" - }, - "\\zeta": { - font: "main", - group: "mathord", - replace: "\u03b6" - }, - "\\eta": { - font: "main", - group: "mathord", - replace: "\u03b7" - }, - "\\theta": { - font: "main", - group: "mathord", - replace: "\u03b8" - }, - "\\iota": { - font: "main", - group: "mathord", - replace: "\u03b9" - }, - "\\kappa": { - font: "main", - group: "mathord", - replace: "\u03ba" - }, - "\\lambda": { - font: "main", - group: "mathord", - replace: "\u03bb" - }, - "\\mu": { - font: "main", - group: "mathord", - replace: "\u03bc" - }, - "\\nu": { - font: "main", - group: "mathord", - replace: "\u03bd" - }, - "\\xi": { - font: "main", - group: "mathord", - replace: "\u03be" - }, - "\\omicron": { - font: "main", - group: "mathord", - replace: "o" - }, - "\\pi": { - font: "main", - group: "mathord", - replace: "\u03c0" - }, - "\\rho": { - font: "main", - group: "mathord", - replace: "\u03c1" - }, - "\\sigma": { - font: "main", - group: "mathord", - replace: "\u03c3" - }, - "\\tau": { - font: "main", - group: "mathord", - replace: "\u03c4" - }, - "\\upsilon": { - font: "main", - group: "mathord", - replace: "\u03c5" - }, - "\\phi": { - font: "main", - group: "mathord", - replace: "\u03d5" - }, - "\\chi": { - font: "main", - group: "mathord", - replace: "\u03c7" - }, - "\\psi": { - font: "main", - group: "mathord", - replace: "\u03c8" - }, - "\\omega": { - font: "main", - group: "mathord", - replace: "\u03c9" - }, - "\\varepsilon": { - font: "main", - group: "mathord", - replace: "\u03b5" - }, - "\\vartheta": { - font: "main", - group: "mathord", - replace: "\u03d1" - }, - "\\varpi": { - font: "main", - group: "mathord", - replace: "\u03d6" - }, - "\\varrho": { - font: "main", - group: "mathord", - replace: "\u03f1" - }, - "\\varsigma": { - font: "main", - group: "mathord", - replace: "\u03c2" - }, - "\\varphi": { - font: "main", - group: "mathord", - replace: "\u03c6" - }, - "*": { - font: "main", - group: "bin", - replace: "\u2217" - }, - "+": { - font: "main", - group: "bin" - }, - "-": { - font: "main", - group: "bin", - replace: "\u2212" - }, - "\\cdot": { - font: "main", - group: "bin", - replace: "\u22c5" - }, - "\\circ": { - font: "main", - group: "bin", - replace: "\u2218" - }, - "\\div": { - font: "main", - group: "bin", - replace: "\u00f7" - }, - "\\pm": { - font: "main", - group: "bin", - replace: "\u00b1" - }, - "\\times": { - font: "main", - group: "bin", - replace: "\u00d7" - }, - "(": { - font: "main", - group: "open" - }, - "[": { - font: "main", - group: "open" - }, - "\\langle": { - font: "main", - group: "open", - replace: "\u27e8" - }, - "\\lvert": { - font: "main", - group: "open", - replace: "|" - }, - ")": { - font: "main", - group: "close" - }, - "]": { - font: "main", - group: "close" - }, - "?": { - font: "main", - group: "close" - }, - "!": { - font: "main", - group: "close" - }, - "\\rangle": { - font: "main", - group: "close", - replace: "\u27e9" - }, - "\\rvert": { - font: "main", - group: "close", - replace: "|" - }, - "=": { - font: "main", - group: "rel" - }, - "<": { - font: "main", - group: "rel" - }, - ">": { - font: "main", - group: "rel" - }, - ":": { - font: "main", - group: "rel" - }, - "\\approx": { - font: "main", - group: "rel", - replace: "\u2248" - }, - "\\cong": { - font: "main", - group: "rel", - replace: "\u2245" - }, - "\\ge": { - font: "main", - group: "rel", - replace: "\u2265" - }, - "\\geq": { - font: "main", - group: "rel", - replace: "\u2265" - }, - "\\gets": { - font: "main", - group: "rel", - replace: "\u2190" - }, - "\\in": { - font: "main", - group: "rel", - replace: "\u2208" - }, - "\\leftarrow": { - font: "main", - group: "rel", - replace: "\u2190" - }, - "\\le": { - font: "main", - group: "rel", - replace: "\u2264" - }, - "\\leq": { - font: "main", - group: "rel", - replace: "\u2264" - }, - "\\ne": { - font: "main", - group: "rel", - replace: "\u2260" - }, - "\\neq": { - font: "main", - group: "rel", - replace: "\u2260" - }, - "\\rightarrow": { - font: "main", - group: "rel", - replace: "\u2192" - }, - "\\to": { - font: "main", - group: "rel", - replace: "\u2192" - }, - "\\ngeq": { - font: "ams", - group: "rel", - replace: "\u2271" - }, - "\\nleq": { - font: "ams", - group: "rel", - replace: "\u2270" - }, - "\\!": { - font: "main", - group: "spacing" - }, - "\\ ": { - font: "main", - group: "spacing", - replace: "\u00a0" - }, - "\\,": { - font: "main", - group: "spacing" - }, - "\\:": { - font: "main", - group: "spacing" - }, - "\\;": { - font: "main", - group: "spacing" - }, - "\\enspace": { - font: "main", - group: "spacing" - }, - "\\qquad": { - font: "main", - group: "spacing" - }, - "\\quad": { - font: "main", - group: "spacing" - }, - "\\space": { - font: "main", - group: "spacing", - replace: "\u00a0" - }, - ",": { - font: "main", - group: "punct" - }, - ";": { - font: "main", - group: "punct" - }, - "\\colon": { - font: "main", - group: "punct", - replace: ":" - }, - "\\barwedge": { - font: "ams", - group: "textord", - replace: "\u22bc" - }, - "\\veebar": { - font: "ams", - group: "textord", - replace: "\u22bb" - }, - "\\odot": { - font: "main", - group: "textord", - replace: "\u2299" - }, - "\\oplus": { - font: "main", - group: "textord", - replace: "\u2295" - }, - "\\otimes": { - font: "main", - group: "textord", - replace: "\u2297" - }, - "\\oslash": { - font: "main", - group: "textord", - replace: "\u2298" - }, - "\\circledcirc": { - font: "ams", - group: "textord", - replace: "\u229a" - }, - "\\boxdot": { - font: "ams", - group: "textord", - replace: "\u22a1" - }, - "\\bigtriangleup": { - font: "main", - group: "textord", - replace: "\u25b3" - }, - "\\bigtriangledown": { - font: "main", - group: "textord", - replace: "\u25bd" - }, - "\\dagger": { - font: "main", - group: "textord", - replace: "\u2020" - }, - "\\diamond": { - font: "main", - group: "textord", - replace: "\u22c4" - }, - "\\star": { - font: "main", - group: "textord", - replace: "\u22c6" - }, - "\\triangleleft": { - font: "main", - group: "textord", - replace: "\u25c3" - }, - "\\triangleright": { - font: "main", - group: "textord", - replace: "\u25b9" + "math": { + "`": { + font: "main", + group: "textord", + replace: "\u2018" + }, + "\\$": { + font: "main", + group: "textord", + replace: "$" + }, + "\\%": { + font: "main", + group: "textord", + replace: "%" + }, + "\\angle": { + font: "main", + group: "textord", + replace: "\u2220" + }, + "\\infty": { + font: "main", + group: "textord", + replace: "\u221e" + }, + "\\prime": { + font: "main", + group: "textord", + replace: "\u2032" + }, + "\\triangle": { + font: "main", + group: "textord", + replace: "\u25b3" + }, + "\\Gamma": { + font: "main", + group: "textord", + replace: "\u0393" + }, + "\\Delta": { + font: "main", + group: "textord", + replace: "\u0394" + }, + "\\Theta": { + font: "main", + group: "textord", + replace: "\u0398" + }, + "\\Lambda": { + font: "main", + group: "textord", + replace: "\u039b" + }, + "\\Xi": { + font: "main", + group: "textord", + replace: "\u039e" + }, + "\\Pi": { + font: "main", + group: "textord", + replace: "\u03a0" + }, + "\\Sigma": { + font: "main", + group: "textord", + replace: "\u03a3" + }, + "\\Upsilon": { + font: "main", + group: "textord", + replace: "\u03a5" + }, + "\\Phi": { + font: "main", + group: "textord", + replace: "\u03a6" + }, + "\\Psi": { + font: "main", + group: "textord", + replace: "\u03a8" + }, + "\\Omega": { + font: "main", + group: "textord", + replace: "\u03a9" + }, + "\\alpha": { + font: "main", + group: "mathord", + replace: "\u03b1" + }, + "\\beta": { + font: "main", + group: "mathord", + replace: "\u03b2" + }, + "\\gamma": { + font: "main", + group: "mathord", + replace: "\u03b3" + }, + "\\delta": { + font: "main", + group: "mathord", + replace: "\u03b4" + }, + "\\epsilon": { + font: "main", + group: "mathord", + replace: "\u03f5" + }, + "\\zeta": { + font: "main", + group: "mathord", + replace: "\u03b6" + }, + "\\eta": { + font: "main", + group: "mathord", + replace: "\u03b7" + }, + "\\theta": { + font: "main", + group: "mathord", + replace: "\u03b8" + }, + "\\iota": { + font: "main", + group: "mathord", + replace: "\u03b9" + }, + "\\kappa": { + font: "main", + group: "mathord", + replace: "\u03ba" + }, + "\\lambda": { + font: "main", + group: "mathord", + replace: "\u03bb" + }, + "\\mu": { + font: "main", + group: "mathord", + replace: "\u03bc" + }, + "\\nu": { + font: "main", + group: "mathord", + replace: "\u03bd" + }, + "\\xi": { + font: "main", + group: "mathord", + replace: "\u03be" + }, + "\\omicron": { + font: "main", + group: "mathord", + replace: "o" + }, + "\\pi": { + font: "main", + group: "mathord", + replace: "\u03c0" + }, + "\\rho": { + font: "main", + group: "mathord", + replace: "\u03c1" + }, + "\\sigma": { + font: "main", + group: "mathord", + replace: "\u03c3" + }, + "\\tau": { + font: "main", + group: "mathord", + replace: "\u03c4" + }, + "\\upsilon": { + font: "main", + group: "mathord", + replace: "\u03c5" + }, + "\\phi": { + font: "main", + group: "mathord", + replace: "\u03d5" + }, + "\\chi": { + font: "main", + group: "mathord", + replace: "\u03c7" + }, + "\\psi": { + font: "main", + group: "mathord", + replace: "\u03c8" + }, + "\\omega": { + font: "main", + group: "mathord", + replace: "\u03c9" + }, + "\\varepsilon": { + font: "main", + group: "mathord", + replace: "\u03b5" + }, + "\\vartheta": { + font: "main", + group: "mathord", + replace: "\u03d1" + }, + "\\varpi": { + font: "main", + group: "mathord", + replace: "\u03d6" + }, + "\\varrho": { + font: "main", + group: "mathord", + replace: "\u03f1" + }, + "\\varsigma": { + font: "main", + group: "mathord", + replace: "\u03c2" + }, + "\\varphi": { + font: "main", + group: "mathord", + replace: "\u03c6" + }, + "*": { + font: "main", + group: "bin", + replace: "\u2217" + }, + "+": { + font: "main", + group: "bin" + }, + "-": { + font: "main", + group: "bin", + replace: "\u2212" + }, + "\\cdot": { + font: "main", + group: "bin", + replace: "\u22c5" + }, + "\\circ": { + font: "main", + group: "bin", + replace: "\u2218" + }, + "\\div": { + font: "main", + group: "bin", + replace: "\u00f7" + }, + "\\pm": { + font: "main", + group: "bin", + replace: "\u00b1" + }, + "\\times": { + font: "main", + group: "bin", + replace: "\u00d7" + }, + "(": { + font: "main", + group: "open" + }, + "[": { + font: "main", + group: "open" + }, + "\\langle": { + font: "main", + group: "open", + replace: "\u27e8" + }, + "\\lvert": { + font: "main", + group: "open", + replace: "|" + }, + ")": { + font: "main", + group: "close" + }, + "]": { + font: "main", + group: "close" + }, + "?": { + font: "main", + group: "close" + }, + "!": { + font: "main", + group: "close" + }, + "\\rangle": { + font: "main", + group: "close", + replace: "\u27e9" + }, + "\\rvert": { + font: "main", + group: "close", + replace: "|" + }, + "=": { + font: "main", + group: "rel" + }, + "<": { + font: "main", + group: "rel" + }, + ">": { + font: "main", + group: "rel" + }, + ":": { + font: "main", + group: "rel" + }, + "\\approx": { + font: "main", + group: "rel", + replace: "\u2248" + }, + "\\cong": { + font: "main", + group: "rel", + replace: "\u2245" + }, + "\\ge": { + font: "main", + group: "rel", + replace: "\u2265" + }, + "\\geq": { + font: "main", + group: "rel", + replace: "\u2265" + }, + "\\gets": { + font: "main", + group: "rel", + replace: "\u2190" + }, + "\\in": { + font: "main", + group: "rel", + replace: "\u2208" + }, + "\\leftarrow": { + font: "main", + group: "rel", + replace: "\u2190" + }, + "\\le": { + font: "main", + group: "rel", + replace: "\u2264" + }, + "\\leq": { + font: "main", + group: "rel", + replace: "\u2264" + }, + "\\ne": { + font: "main", + group: "rel", + replace: "\u2260" + }, + "\\neq": { + font: "main", + group: "rel", + replace: "\u2260" + }, + "\\rightarrow": { + font: "main", + group: "rel", + replace: "\u2192" + }, + "\\to": { + font: "main", + group: "rel", + replace: "\u2192" + }, + "\\ngeq": { + font: "ams", + group: "rel", + replace: "\u2271" + }, + "\\nleq": { + font: "ams", + group: "rel", + replace: "\u2270" + }, + "\\!": { + font: "main", + group: "spacing" + }, + "\\ ": { + font: "main", + group: "spacing", + replace: "\u00a0" + }, + "\\,": { + font: "main", + group: "spacing" + }, + "\\:": { + font: "main", + group: "spacing" + }, + "\\;": { + font: "main", + group: "spacing" + }, + "\\enspace": { + font: "main", + group: "spacing" + }, + "\\qquad": { + font: "main", + group: "spacing" + }, + "\\quad": { + font: "main", + group: "spacing" + }, + "\\space": { + font: "main", + group: "spacing", + replace: "\u00a0" + }, + ",": { + font: "main", + group: "punct" + }, + ";": { + font: "main", + group: "punct" + }, + "\\colon": { + font: "main", + group: "punct", + replace: ":" + }, + "\\barwedge": { + font: "ams", + group: "textord", + replace: "\u22bc" + }, + "\\veebar": { + font: "ams", + group: "textord", + replace: "\u22bb" + }, + "\\odot": { + font: "main", + group: "textord", + replace: "\u2299" + }, + "\\oplus": { + font: "main", + group: "textord", + replace: "\u2295" + }, + "\\otimes": { + font: "main", + group: "textord", + replace: "\u2297" + }, + "\\oslash": { + font: "main", + group: "textord", + replace: "\u2298" + }, + "\\circledcirc": { + font: "ams", + group: "textord", + replace: "\u229a" + }, + "\\boxdot": { + font: "ams", + group: "textord", + replace: "\u22a1" + }, + "\\bigtriangleup": { + font: "main", + group: "textord", + replace: "\u25b3" + }, + "\\bigtriangledown": { + font: "main", + group: "textord", + replace: "\u25bd" + }, + "\\dagger": { + font: "main", + group: "textord", + replace: "\u2020" + }, + "\\diamond": { + font: "main", + group: "textord", + replace: "\u22c4" + }, + "\\star": { + font: "main", + group: "textord", + replace: "\u22c6" + }, + "\\triangleleft": { + font: "main", + group: "textord", + replace: "\u25c3" + }, + "\\triangleright": { + font: "main", + group: "textord", + replace: "\u25b9" + } + }, + "text": { + "\\ ": { + font: "main", + group: "spacing", + replace: "\u00a0" + }, + " ": { + font: "main", + group: "spacing", + replace: "\u00a0" + } } }; -var textSymbols = "0123456789/|@.\""; -for (var i = 0; i < textSymbols.length; i++) { - var ch = textSymbols.charAt(i); - symbols[ch] = { +var mathTextSymbols = "0123456789/|@.\""; +for (var i = 0; i < mathTextSymbols.length; i++) { + var ch = mathTextSymbols.charAt(i); + symbols["math"][ch] = { font: "main", group: "textord" }; } -var mathSymbols = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; -for (var i = 0; i < mathSymbols.length; i++) { - var ch = mathSymbols.charAt(i); - symbols[ch] = { +var textSymbols = "0123456789`!@*()-=+[]'\";:?/.,"; +for (var i = 0; i < textSymbols.length; i++) { + var ch = textSymbols.charAt(i); + symbols["text"][ch] = { + font: "main", + group: "textord" + }; +} + +var letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +for (var i = 0; i < letters.length; i++) { + var ch = letters.charAt(i); + symbols["math"][ch] = { font: "main", group: "mathord" }; + symbols["text"][ch] = { + font: "main", + group: "textord" + }; } module.exports = symbols; diff --git a/test/huxley/Huxleyfile b/test/huxley/Huxleyfile index 77c6ff6bb..18116a139 100644 --- a/test/huxley/Huxleyfile +++ b/test/huxley/Huxleyfile @@ -34,5 +34,8 @@ url=http://localhost:7936/test/huxley/test.html?m=\Huge{x}\LARGE{y}\normalsize{z [SizingBaseline] url=http://localhost:7936/test/huxley/test.html?m=\tiny{a+b}a+b\Huge{a+b}&pre=x&post=M +[Text] +url=http://localhost:7936/test/huxley/test.html?m=\frac{a}{b}\text{c {ab} \ e}+fg + [KaTeX] -url=http://localhost:7936/test/huxley/test.html?m=\KaTeX \ No newline at end of file +url=http://localhost:7936/test/huxley/test.html?m=\KaTeX diff --git a/test/huxley/Text.huxley/record.json b/test/huxley/Text.huxley/record.json new file mode 100644 index 000000000..9369c51e8 --- /dev/null +++ b/test/huxley/Text.huxley/record.json @@ -0,0 +1 @@ +{"py/object": "huxley.run.Test", "screen_size": {"py/tuple": [1024, 768]}, "steps": [{"py/object": "huxley.steps.ScreenshotTestStep", "index": 0, "offset_time": 0}]} diff --git a/test/huxley/Text.huxley/screenshot0.png b/test/huxley/Text.huxley/screenshot0.png new file mode 100644 index 0000000000000000000000000000000000000000..f5e477fa6b60710ed35e04fa775870a23c9906ff GIT binary patch literal 12747 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 literal 0 HcmV?d00001 diff --git a/test/katex-tests.js b/test/katex-tests.js index f75ad72c6..95b366e73 100644 --- a/test/katex-tests.js +++ b/test/katex-tests.js @@ -447,3 +447,52 @@ describe("A sizing parser", function() { }).toThrow(); }); }); + +describe("A text parser", function() { + var textExpression = "\\text{a b}"; + var badTextExpression = "\\text{a b%}"; + var nestedTextExpression = "\\text{a {b} \\blue{c}}"; + var spaceTextExpression = "\\text{ a \\ }"; + + it("should not fail", function() { + expect(function() { + parseTree(textExpression); + }).not.toThrow(); + }); + + it("should produce a text", function() { + var parse = parseTree(textExpression)[0]; + + expect(parse.type).toMatch("text"); + expect(parse.value).toBeDefined(); + }); + + it("should produce textords instead of mathords", function() { + var parse = parseTree(textExpression)[0]; + var group = parse.value.value; + + expect(group[0].type).toMatch("textord"); + }); + + it("should not parse bad text", function() { + expect(function() { + parseTree(badTextExpression); + }).toThrow(); + }); + + it("should parse nested expressions", function() { + expect(function() { + parseTree(nestedTextExpression); + }).not.toThrow(); + }); + + it("should contract spaces", function() { + var parse = parseTree(spaceTextExpression)[0]; + var group = parse.value.value; + + expect(group[0].type).toMatch("spacing"); + expect(group[1].type).toMatch("textord"); + expect(group[2].type).toMatch("spacing"); + expect(group[3].type).toMatch("spacing"); + }); +});