From e46dd418b3c6782a82c0f3965101d0a21f12aa5c Mon Sep 17 00:00:00 2001 From: Ben Alpert Date: Fri, 30 May 2014 12:29:32 -0700 Subject: [PATCH] Ignore whitespace following `\text` Summary: In something like `\text {hello, world}` we want to ignore the first space but not the second. This suggests to me that perhaps we shouldn't be in text-lexing mode until we actually see the first curly brace, so this changes us to do that. Note that this disallows doing unbraced text things now; it seemed nontrivial to lex a single text character while ignoring spaces. We should probably fix it sometime, but for now we'll fall back to MathJax anyway so I'm not super concerned. We should also add a huxley test for this. Test Plan: `\text {2x 2}` rendered `2x 2` in a non-italic font. Reviewers: jack, emily Reviewed By: emily Differential Revision: http://phabricator.khanacademy.org/D9376 --- Parser.js | 24 +++++++++++++++++++++++- test/katex-tests.js | 14 ++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/Parser.js b/Parser.js index c06e7174c..3329ccae5 100644 --- a/Parser.js +++ b/Parser.js @@ -223,6 +223,28 @@ Parser.prototype.parseColorGroup = function(pos, mode) { } }; +// Parses a text group, which looks like "{#ffffff}" +Parser.prototype.parseTextGroup = function(pos, mode) { + var start = this.lexer.lex(pos, mode); + // Try to parse an open brace + if (start.type === "{") { + // Parse the text + var text = this.parseExpression(start.position, "text"); + // Make sure we get a close brace + var closeBrace = this.lexer.lex(text.position, mode); + this.expect(closeBrace, "}"); + return new ParseResult( + new ParseNode("ordgroup", text.result, "text"), + closeBrace.position); + } else { + // It has to have an open brace, so if it doesn't we throw + throw new ParseError( + "There must be braces around text", + this.lexer, pos + ); + } +}; + // A list of 1-argument color functions var colorFuncs = [ "\\blue", "\\orange", "\\pink", "\\red", "\\green", "\\gray", "\\purple" @@ -333,7 +355,7 @@ Parser.prototype.parseNucleus = function(pos, mode) { ); } } else if (mode === "math" && nucleus.type === "\\text") { - var group = this.parseGroup(nucleus.position, "text"); + var group = this.parseTextGroup(nucleus.position, mode); if (group) { return new ParseResult( new ParseNode(nucleus.type.slice(1), group.result, mode), diff --git a/test/katex-tests.js b/test/katex-tests.js index 6b0ba15b6..6c2759c39 100644 --- a/test/katex-tests.js +++ b/test/katex-tests.js @@ -451,8 +451,10 @@ describe("A sizing parser", function() { describe("A text parser", function() { var textExpression = "\\text{a b}"; var badTextExpression = "\\text{a b%}"; + var badTextExpression2 = "\\text x"; var nestedTextExpression = "\\text{a {b} \\blue{c}}"; var spaceTextExpression = "\\text{ a \\ }"; + var leadingSpaceTextExpression = "\\text {moo}"; it("should not fail", function() { expect(function() { @@ -478,6 +480,9 @@ describe("A text parser", function() { expect(function() { parseTree(badTextExpression); }).toThrow(); + expect(function() { + parseTree(badTextExpression2); + }).toThrow(); }); it("should parse nested expressions", function() { @@ -495,6 +500,15 @@ describe("A text parser", function() { expect(group[2].type).toMatch("spacing"); expect(group[3].type).toMatch("spacing"); }); + + it("should ignore a space before the text group", function() { + var parse = parseTree(leadingSpaceTextExpression)[0]; + // [m, o, o] + expect(parse.value.value.length).toBe(3); + expect( + parse.value.value.map(function(n) { return n.value; }).join("") + ).toBe("moo"); + }); }); describe("A color parser", function() {