diff --git a/src/environments/array.js b/src/environments/array.js index 134f2d0c..6eaceac5 100644 --- a/src/environments/array.js +++ b/src/environments/array.js @@ -79,6 +79,9 @@ function parseArray( } } + // Start group for first cell + parser.gullet.beginGroup(); + let row = []; const body = [row]; const rowGaps = []; @@ -88,7 +91,11 @@ function parseArray( hLinesBeforeRow.push(getHLines(parser)); while (true) { // eslint-disable-line no-constant-condition + // Parse each cell in its own group (namespace) let cell = parser.parseExpression(false, "\\cr"); + parser.gullet.endGroup(); + parser.gullet.beginGroup(); + cell = { type: "ordgroup", mode: parser.mode, @@ -132,7 +139,12 @@ function parseArray( parser.nextToken); } } + + // End cell group parser.gullet.endGroup(); + // End array group defining \\ + parser.gullet.endGroup(); + return { type: "array", mode: parser.mode, @@ -671,6 +683,7 @@ defineEnvironment({ body: [res], left: delimiters[0], right: delimiters[1], + rightColor: undefined, // \right uninfluenced by \color in array } : res; }, htmlBuilder, @@ -775,6 +788,7 @@ defineEnvironment({ body: [res], left: "\\{", right: ".", + rightColor: undefined, }; }, htmlBuilder, diff --git a/src/functions/color.js b/src/functions/color.js index f2aabe78..305dac9a 100644 --- a/src/functions/color.js +++ b/src/functions/color.js @@ -67,7 +67,13 @@ defineFunction({ handler({parser, breakOnTokenText}, args) { const color = assertNodeType(args[0], "color-token").color; - // If we see a styling function, parse out the implicit body + // Set macro \current@color in current namespace to store the current + // color, mimicking the behavior of color.sty. + // This is currently used just to correctly color a \right + // that follows a \color command. + parser.gullet.macros.set("\\current@color", color); + + // Parse out the implicit body that should be colored. const body = parser.parseExpression(true, breakOnTokenText); return { diff --git a/src/functions/delimsizing.js b/src/functions/delimsizing.js index 2f8a087c..25c26017 100644 --- a/src/functions/delimsizing.js +++ b/src/functions/delimsizing.js @@ -145,10 +145,16 @@ defineFunction({ // \left case below triggers parsing of \right in // `const right = parser.parseFunction();` // uses this return value. + const color = context.parser.gullet.macros.get("\\current@color"); + if (color && typeof color !== "string") { + throw new ParseError( + "\\current@color set to non-string in \\right"); + } return { type: "leftright-right", mode: context.parser.mode, delim: checkDelimiter(args[0], context).text, + color, // undefined if not set via \color }; }, }); @@ -178,6 +184,7 @@ defineFunction({ body, left: delim.text, right: right.delim, + rightColor: right.color, }; }, htmlBuilder: (group, options) => { @@ -241,12 +248,14 @@ defineFunction({ } let rightDelim; - // Same for the right delimiter + // Same for the right delimiter, but using color specified by \color if (group.right === ".") { rightDelim = html.makeNullDelimiter(options, ["mclose"]); } else { + const colorOptions = group.rightColor ? + options.withColor(group.rightColor) : options; rightDelim = delimiter.leftRightDelim( - group.right, innerHeight, innerDepth, options, + group.right, innerHeight, innerDepth, colorOptions, group.mode, ["mclose"]); } // Add it to the end of the expression. @@ -273,6 +282,10 @@ defineFunction({ rightNode.setAttribute("fence", "true"); + if (group.rightColor) { + rightNode.setAttribute("mathcolor", group.rightColor); + } + inner.push(rightNode); } diff --git a/src/parseNode.js b/src/parseNode.js index 5337ebbf..5b2f0c4b 100644 --- a/src/parseNode.js +++ b/src/parseNode.js @@ -318,12 +318,14 @@ type ParseNodeTypes = { body: AnyParseNode[], left: string, right: string, + rightColor: ?string, // undefined means "inherit" |}, "leftright-right": {| type: "leftright-right", mode: Mode, loc?: ?SourceLocation, delim: string, + color: ?string, // undefined means "inherit" |}, "mathchoice": {| type: "mathchoice", diff --git a/test/katex-spec.js b/test/katex-spec.js index 9cdf8ae5..5426be68 100644 --- a/test/katex-spec.js +++ b/test/katex-spec.js @@ -3123,6 +3123,21 @@ describe("A macro expander", function() { .toParseLike`11\sqrt[2]{2}11`; }); + it("array cells generate groups", () => { + expect`\def\x{1}\begin{matrix}\x&\def\x{2}\x&\x\end{matrix}` + .toParseLike`\begin{matrix}1&2&1\end{matrix}`; + }); + + // TODO: This doesn't yet work; before the environment gets called, + // {matrix} gets consumed which means that the \def gets executed, before + // we can create a group. :-( Issue #1989 + /* + it("array cells generate groups", () => { + expect`\def\x{1}\begin{matrix}\def\x{2}&\x\end{matrix}` + .toParseLike`\begin{matrix}&1\end{matrix}`; + }); + */ + it("\\gdef changes settings.macros", () => { const macros = {}; expect`\gdef\foo{1}`.toParse(new Settings({macros})); diff --git a/test/screenshotter/images/ColorImplicit-chrome.png b/test/screenshotter/images/ColorImplicit-chrome.png index 1b153a81..d2f10d2d 100644 Binary files a/test/screenshotter/images/ColorImplicit-chrome.png and b/test/screenshotter/images/ColorImplicit-chrome.png differ diff --git a/test/screenshotter/images/ColorImplicit-firefox.png b/test/screenshotter/images/ColorImplicit-firefox.png index b136ee3a..5467711f 100644 Binary files a/test/screenshotter/images/ColorImplicit-firefox.png and b/test/screenshotter/images/ColorImplicit-firefox.png differ diff --git a/test/screenshotter/ss_data.yaml b/test/screenshotter/ss_data.yaml index 2bd841b3..b00638ac 100644 --- a/test/screenshotter/ss_data.yaml +++ b/test/screenshotter/ss_data.yaml @@ -77,7 +77,11 @@ Cases: | Colors: tex: \blue{a}\textcolor{#0f0}{b}\textcolor{red}{c} nolatex: different syntax and different scope -ColorImplicit: bl{ack\color{red}red\textcolor{green}{green}red\color{blue}blue}black +ColorImplicit: + \begin{array}{l} + bl{ack\color{red}red\textcolor{green}{green}red\color{blue}blue}black \\ + black\left(black\color{red}red\right)black + \end{array} ColorSpacing: \textcolor{red}{\displaystyle \int x} + 1 Colorbox: a \colorbox{teal} B \fcolorbox{blue}{red}{C} e+\colorbox{teal}x DashesAndQuotes: |