diff --git a/src/macros.js b/src/macros.js index 4554a42f..c4b7f7a0 100644 --- a/src/macros.js +++ b/src/macros.js @@ -36,6 +36,11 @@ export interface MacroContextInterface { */ popToken(): Token; + /** + * Consume all following space tokens, without expansion. + */ + consumeSpaces(): void; + /** * Expand the next token only once (if possible), and return the resulting * top token on the stack (without removing anything from the stack). @@ -108,10 +113,12 @@ defineMacro("\\@secondoftwo", function(context) { }); // LaTeX's \@ifnextchar{#1}{#2}{#3} looks ahead to the next (unexpanded) -// symbol. If it matches #1, then the macro expands to #2; otherwise, #3. -// Note, however, that it does not consume the next symbol in either case. +// symbol that isn't a space, consuming any spaces but not consuming the +// first nonspace character. If that nonspace character matches #1, then +// the macro expands to #2; otherwise, it expands to #3. defineMacro("\\@ifnextchar", function(context) { const args = context.consumeArgs(3); // symbol, if, else + context.consumeSpaces(); const nextToken = context.future(); if (args[0].length === 1 && args[0][0].text === nextToken.text) { return {tokens: args[1], numArgs: 0}; diff --git a/test/katex-spec.js b/test/katex-spec.js index a418a133..f4637f10 100644 --- a/test/katex-spec.js +++ b/test/katex-spec.js @@ -3008,11 +3008,16 @@ describe("A macro expander", function() { expect`\@ifstar{yes}{no}?!`.toParseLike`no?!`; }); - it("\\@ifnextchar should not consume anything", function() { + it("\\@ifnextchar should not consume nonspaces", function() { expect`\@ifnextchar!{yes}{no}!!`.toParseLike`yes!!`; expect`\@ifnextchar!{yes}{no}?!`.toParseLike`no?!`; }); + it("\\@ifnextchar should consume spaces", function() { + expect`\def\x#1{\@ifnextchar x{yes}{no}}\x{}x\x{} x` + .toParseLike`yesxyesx`; + }); + it("\\@ifstar should consume star but nothing else", function() { expect`\@ifstar{yes}{no}*!`.toParseLike`yes!`; expect`\@ifstar{yes}{no}?!`.toParseLike`no?!`;