diff --git a/Parser.js b/Parser.js index 4fec946ee..0f18fe4bc 100644 --- a/Parser.js +++ b/Parser.js @@ -242,6 +242,11 @@ var sizeFuncs = [ "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge" ]; +// A list of the style-changing functions, for use in parseImplicitGroup +var styleFuncs = [ + "\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle" +]; + // 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 // is used for functions that appear to affect the current style, like \Large or @@ -259,7 +264,9 @@ Parser.prototype.parseImplicitGroup = function(pos, mode) { return this.parseFunction(pos, mode); } - if (start.result.result === "\\left") { + var func = start.result.result; + + if (func === "\\left") { // If we see a left: // Parse the entire left function (including the delimiter) var left = this.parseFunction(pos, mode); @@ -282,17 +289,28 @@ Parser.prototype.parseImplicitGroup = function(pos, mode) { } else { throw new ParseError("Missing \\right", this.lexer, body.position); } - } else if (start.result.result === "\\right") { + } else if (func === "\\right") { // If we see a right, explicitly fail the parsing here so the \left // handling ends the group return null; - } else if (utils.contains(sizeFuncs, start.result.result)) { + } else if (utils.contains(sizeFuncs, func)) { // If we see a sizing function, parse out the implict body var body = this.handleExpressionBody(start.result.position, mode); return new ParseResult( new ParseNode("sizing", { // Figure out what size to use based on the list of functions above - size: "size" + (utils.indexOf(sizeFuncs, start.result.result) + 1), + size: "size" + (utils.indexOf(sizeFuncs, func) + 1), + value: body.body + }, mode), + body.position); + } else if (utils.contains(styleFuncs, func)) { + // If we see a styling function, parse out the implict body + var body = this.handleExpressionBody(start.result.position, mode); + return new ParseResult( + new ParseNode("styling", { + // Figure out what style to use by pulling out the style from + // the function name + style: func.slice(1, func.length - 5), value: body.body }, mode), body.position); diff --git a/buildTree.js b/buildTree.js index d90f4c8e5..3a5f5d2db 100644 --- a/buildTree.js +++ b/buildTree.js @@ -54,6 +54,8 @@ var getTypeOfGroup = function(group) { return getTypeOfGroup(group.value.value); } else if (group.type === "sizing") { return getTypeOfGroup(group.value.value); + } else if (group.type === "styling") { + return getTypeOfGroup(group.value.value); } else if (group.type === "delimsizing") { return groupToType[group.value.delimType]; } else { @@ -547,6 +549,22 @@ var groupTypes = { return span; }, + styling: function(group, options, prev) { + var style = { + "display": Style.DISPLAY, + "text": Style.TEXT, + "script": Style.SCRIPT, + "scriptscript": Style.SCRIPTSCRIPT + }; + + var newStyle = style[group.value.style]; + + var inner = buildExpression( + group.value.value, options.withStyle(newStyle), prev); + + return makeSpan([options.style.reset(), newStyle.cls()], inner); + }, + delimsizing: function(group, options, prev) { var delim = group.value.value; diff --git a/functions.js b/functions.js index 20da6f9eb..0d6e8cac9 100644 --- a/functions.js +++ b/functions.js @@ -310,7 +310,7 @@ var duplicatedFunctions = [ } }, - // Sizing functions + // Sizing functions (handled in Parser.js explicitly, hence no handler) { funcs: [ "\\tiny", "\\scriptsize", "\\footnotesize", "\\small", @@ -319,6 +319,18 @@ var duplicatedFunctions = [ data: { numArgs: 0 } + }, + + // Style changing functions (handled in Parser.js explicitly, hence no + // handler) + { + funcs: [ + "\\displaystyle", "\\textstyle", "\\scriptstyle", + "\\scriptscriptstyle" + ], + data: { + numArgs: 0 + } } ]; diff --git a/test/huxley/DisplayStyle.hux/firefox-1.png b/test/huxley/DisplayStyle.hux/firefox-1.png new file mode 100644 index 000000000..2c1965e8c Binary files /dev/null and b/test/huxley/DisplayStyle.hux/firefox-1.png differ diff --git a/test/huxley/DisplayStyle.hux/record.json b/test/huxley/DisplayStyle.hux/record.json new file mode 100644 index 000000000..3cae6ac65 --- /dev/null +++ b/test/huxley/DisplayStyle.hux/record.json @@ -0,0 +1,5 @@ +[ + { + "action": "screenshot" + } +] diff --git a/test/huxley/Huxleyfile.json b/test/huxley/Huxleyfile.json index 1d7c0a880..8b8f01337 100644 --- a/test/huxley/Huxleyfile.json +++ b/test/huxley/Huxleyfile.json @@ -159,5 +159,11 @@ "name": "Sqrt", "screenSize": [1024, 768], "url": "http://localhost:7936/test/huxley/test.html?m=\\sqrt{\\sqrt{\\sqrt{x}}}_{\\sqrt{\\sqrt{x}}}^{\\sqrt{\\sqrt{\\sqrt{x}}}^{\\sqrt{\\sqrt{\\sqrt{x}}}}}" + }, + + { + "name": "DisplayStyle", + "screenSize": [1024, 768], + "url": "http://localhost:7936/test/huxley/test.html?m={\\displaystyle\\sqrt{x}}{\\sqrt{x}}{\\displaystyle \\frac12}{\\frac12}{\\displaystyle x^1_2}{x^1_2}" } ] diff --git a/test/katex-tests.js b/test/katex-tests.js index 7d8900984..4c0d4fc9e 100644 --- a/test/katex-tests.js +++ b/test/katex-tests.js @@ -916,3 +916,36 @@ describe("A TeX-compliant parser", function() { } }); }); + +describe("A style change parser", function() { + it("should not fail", function() { + expect("\\displaystyle x").toParse(); + expect("\\textstyle x").toParse(); + expect("\\scriptstyle x").toParse(); + expect("\\scriptscriptstyle x").toParse(); + }); + + it("should produce the correct style", function() { + var displayParse = parseTree("\\displaystyle x")[0]; + expect(displayParse.value.style).toMatch("display"); + + var scriptscriptParse = parseTree("\\scriptscriptstyle x")[0]; + expect(scriptscriptParse.value.style).toMatch("scriptscript"); + }); + + it("should only change the style within its group", function() { + var text = "a b { c d \\displaystyle e f } g h"; + expect(text).toParse(); + + var parse = parseTree(text); + + var displayNode = parse[2].value[2]; + + expect(displayNode.type).toMatch("styling"); + + var displayBody = displayNode.value.value; + + expect(displayBody.length).toEqual(2); + expect(displayBody[0].value).toMatch("e"); + }); +});