mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-06 03:38:39 +00:00
\def support (and \gdef and \global\def) (#1348)
* Nested environments of macro definitions * Rename environment -> namespace * \def support * Clean up \df@tag at beginning * \global\def support * Fix \global via new setMacro helper * Fix caching behavior and build array on top of it Also avoid double lookup of macros * Add tests * Add argument tests * Remove global pointer * Note about macros object being modified * add __defineMacro * Add \global\def test * More \global tests * Constant-time lookup Rewrite to use an "undo" stack similar to TeX, so get and set are constant-time operations. get() still has to check two objects: one with all current settings, and then the built-ins. Local set() sets the current value and (when appropriate) adds an undo operation to the undo stack. Global set() still takes time linear in the number of groups, possibly changing the undo operation at every level. `Namespace` now refers to a space of things like macros or lengths. * Add \def to-dos * Put optional arguments in their own group * Rename `pushNamespace` -> `beginGroup` * Wrap each expression in a group namespace * Add comments
This commit is contained in:
committed by
Kevin Barabash
parent
3ec752f5f1
commit
acccce801d
@@ -11,6 +11,9 @@ export const defaultSettings = new Settings({
|
||||
export const strictSettings = new Settings({strict: true});
|
||||
|
||||
export const _getBuilt = function(expr, settings = defaultSettings) {
|
||||
if (settings === defaultSettings) {
|
||||
settings.macros = {};
|
||||
}
|
||||
let rootNode = katex.__renderToDomTree(expr, settings);
|
||||
|
||||
if (rootNode.classes.indexOf('katex-error') >= 0) {
|
||||
|
@@ -757,6 +757,15 @@ describe("A color parser", function() {
|
||||
colorIsTextColor: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("should not define \\color in global context", function() {
|
||||
const macros = {};
|
||||
expect(oldColorExpression).toParseLike("\\textcolor{#fA6}{x}y", {
|
||||
colorIsTextColor: true,
|
||||
macros: macros,
|
||||
});
|
||||
expect(macros).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe("A tie parser", function() {
|
||||
@@ -2690,6 +2699,62 @@ describe("A macro expander", function() {
|
||||
expect("\\gdef\\foo\\bar").toParse();
|
||||
expect("\\gdef{\\foo\\bar}{}").toNotParse();
|
||||
expect("\\gdef{}{}").toNotParse();
|
||||
// TODO: These shouldn't work, but `1` and `{1}` are currently treated
|
||||
// the same, as are `\foo` and `{\foo}`.
|
||||
//expect("\\gdef\\foo1").toNotParse();
|
||||
//expect("\\gdef{\\foo}{}").toNotParse();
|
||||
});
|
||||
|
||||
it("\\def works locally", () => {
|
||||
expect("\\def\\x{1}\\x{\\def\\x{2}\\x{\\def\\x{3}\\x}\\x}\\x")
|
||||
.toParseLike("1{2{3}2}1");
|
||||
expect("\\def\\x{1}\\x\\def\\x{2}\\x{\\def\\x{3}\\x\\def\\x{4}\\x}\\x")
|
||||
.toParseLike("12{34}2");
|
||||
});
|
||||
|
||||
it("\\gdef overrides at all levels", () => {
|
||||
expect("\\def\\x{1}\\x{\\def\\x{2}\\x{\\gdef\\x{3}\\x}\\x}\\x")
|
||||
.toParseLike("1{2{3}3}3");
|
||||
expect("\\def\\x{1}\\x{\\def\\x{2}\\x{\\global\\def\\x{3}\\x}\\x}\\x")
|
||||
.toParseLike("1{2{3}3}3");
|
||||
expect("\\def\\x{1}\\x{\\def\\x{2}\\x{\\gdef\\x{3}\\x\\def\\x{4}\\x}" +
|
||||
"\\x\\def\\x{5}\\x}\\x").toParseLike("1{2{34}35}3");
|
||||
});
|
||||
|
||||
it("\\global needs to followed by \\def", () => {
|
||||
expect("\\global\\def\\foo{}\\foo").toParseLike("");
|
||||
// TODO: This doesn't work yet; \global needs to expand argument.
|
||||
//expect("\\def\\DEF{\\def}\\global\\DEF\\foo{}\\foo").toParseLike("");
|
||||
expect("\\global\\foo").toNotParse();
|
||||
expect("\\global\\bar x").toNotParse();
|
||||
});
|
||||
|
||||
it("Macro arguments do not generate groups", () => {
|
||||
expect("\\def\\x{1}\\x\\def\\foo#1{#1}\\foo{\\x\\def\\x{2}\\x}\\x")
|
||||
.toParseLike("1122");
|
||||
});
|
||||
|
||||
it("\\textbf arguments do generate groups", () => {
|
||||
expect("\\def\\x{1}\\x\\textbf{\\x\\def\\x{2}\\x}\\x")
|
||||
.toParseLike("1\\textbf{12}1");
|
||||
});
|
||||
|
||||
it("\\sqrt optional arguments generate groups", () => {
|
||||
expect("\\def\\x{1}\\def\\y{1}\\x\\y" +
|
||||
"\\sqrt[\\def\\x{2}\\x]{\\def\\y{2}\\y}\\x\\y")
|
||||
.toParseLike("11\\sqrt[2]{2}11");
|
||||
});
|
||||
|
||||
it("\\gdef changes settings.macros", () => {
|
||||
const macros = {};
|
||||
expect("\\gdef\\foo{1}").toParse(new Settings({macros}));
|
||||
expect(macros["\\foo"]).toBeTruthy();
|
||||
});
|
||||
|
||||
it("\\def doesn't change settings.macros", () => {
|
||||
const macros = {};
|
||||
expect("\\def\\foo{1}").toParse(new Settings({macros}));
|
||||
expect(macros["\\foo"]).toBeFalsy();
|
||||
});
|
||||
|
||||
// This may change in the future, if we support the extra features of
|
||||
@@ -2967,6 +3032,12 @@ describe("Newlines via \\\\ and \\newline", function() {
|
||||
it("should not allow \\cr at top level", () => {
|
||||
expect("hello \\cr world").toNotBuild();
|
||||
});
|
||||
|
||||
it("array redefines and resets \\\\", () => {
|
||||
expect("a\\\\b\\begin{matrix}x&y\\\\z&w\\end{matrix}\\\\c")
|
||||
.toParseLike("a\\newline b\\begin{matrix}x&y\\cr z&w\\end{matrix}" +
|
||||
"\\newline c");
|
||||
});
|
||||
});
|
||||
|
||||
describe("Symbols", function() {
|
||||
|
Reference in New Issue
Block a user