Skip to content

Commit 6d30fe4

Browse files
authored
fix: \providecommand does not overwrite existing macro (#4000)
Fixes #3928
1 parent 8f47dba commit 6d30fe4

File tree

2 files changed

+19
-14
lines changed

2 files changed

+19
-14
lines changed

src/macros.js

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,9 @@ defineMacro("\\char", function(context) {
146146
// \newcommand{\macro}[args]{definition}
147147
// \renewcommand{\macro}[args]{definition}
148148
// TODO: Optional arguments: \newcommand{\macro}[args][default]{definition}
149-
const newcommand = (context, existsOK: boolean, nonexistsOK: boolean) => {
149+
const newcommand = (
150+
context, existsOK: boolean, nonexistsOK: boolean, skipIfExists: boolean
151+
) => {
150152
let arg = context.consumeArg().tokens;
151153
if (arg.length !== 1) {
152154
throw new ParseError(
@@ -181,16 +183,21 @@ const newcommand = (context, existsOK: boolean, nonexistsOK: boolean) => {
181183
arg = context.consumeArg().tokens;
182184
}
183185

184-
// Final arg is the expansion of the macro
185-
context.macros.set(name, {
186-
tokens: arg,
187-
numArgs,
188-
});
186+
if (!(exists && skipIfExists)) {
187+
// Final arg is the expansion of the macro
188+
context.macros.set(name, {
189+
tokens: arg,
190+
numArgs,
191+
});
192+
}
189193
return '';
190194
};
191-
defineMacro("\\newcommand", (context) => newcommand(context, false, true));
192-
defineMacro("\\renewcommand", (context) => newcommand(context, true, false));
193-
defineMacro("\\providecommand", (context) => newcommand(context, true, true));
195+
defineMacro("\\newcommand",
196+
(context) => newcommand(context, false, true, false));
197+
defineMacro("\\renewcommand",
198+
(context) => newcommand(context, true, false, false));
199+
defineMacro("\\providecommand",
200+
(context) => newcommand(context, true, true, true));
194201

195202
// terminal (console) tools
196203
defineMacro("\\message", (context) => {

test/katex-spec.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3659,17 +3659,15 @@ describe("A macro expander", function() {
36593659
expect`\newcommand{\foo}{1}\foo\renewcommand{\foo}{2}\foo`.toParseLike`12`;
36603660
});
36613661

3662-
it("\\providecommand (re)defines macros", () => {
3662+
it("\\providecommand defines but does not redefine macros", () => {
36633663
expect`\providecommand\foo{x^2}\foo+\foo`.toParseLike`x^2+x^2`;
36643664
expect`\providecommand{\foo}{x^2}\foo+\foo`.toParseLike`x^2+x^2`;
3665-
expect`\providecommand\bar{x^2}\bar+\bar`.toParseLike`x^2+x^2`;
3666-
expect`\providecommand{\bar}{x^2}\bar+\bar`.toParseLike`x^2+x^2`;
36673665
expect`\newcommand{\foo}{1}\foo\providecommand{\foo}{2}\foo`
3668-
.toParseLike`12`;
3666+
.toParseLike`11`;
36693667
expect`\providecommand{\foo}{1}\foo\renewcommand{\foo}{2}\foo`
36703668
.toParseLike`12`;
36713669
expect`\providecommand{\foo}{1}\foo\providecommand{\foo}{2}\foo`
3672-
.toParseLike`12`;
3670+
.toParseLike`11`;
36733671
});
36743672

36753673
it("\\newcommand is local", () => {

0 commit comments

Comments
 (0)