UNPKG

39.2 kBJavaScriptView Raw
1// @flow
2/**
3 * Predefined macros for KaTeX.
4 * This can be used to define some commands in terms of others.
5 */
6
7import fontMetricsData from "../submodules/katex-fonts/fontMetricsData";
8import symbols from "./symbols";
9import utils from "./utils";
10import {Token} from "./Token";
11import ParseError from "./ParseError";
12import type Namespace from "./Namespace";
13
14import type {Mode} from "./types";
15
16/**
17 * Provides context to macros defined by functions. Implemented by
18 * MacroExpander.
19 */
20export interface MacroContextInterface {
21 mode: Mode;
22
23 /**
24 * Object mapping macros to their expansions.
25 */
26 macros: Namespace<MacroDefinition>;
27
28 /**
29 * Returns the topmost token on the stack, without expanding it.
30 * Similar in behavior to TeX's `\futurelet`.
31 */
32 future(): Token;
33
34 /**
35 * Remove and return the next unexpanded token.
36 */
37 popToken(): Token;
38
39 /**
40 * Expand the next token only once (if possible), and return the resulting
41 * top token on the stack (without removing anything from the stack).
42 * Similar in behavior to TeX's `\expandafter\futurelet`.
43 */
44 expandAfterFuture(): Token;
45
46 /**
47 * Recursively expand first token, then return first non-expandable token.
48 */
49 expandNextToken(): Token;
50
51 /**
52 * Fully expand the given macro name and return the resulting list of
53 * tokens, or return `undefined` if no such macro is defined.
54 */
55 expandMacro(name: string): Token[] | void;
56
57 /**
58 * Fully expand the given macro name and return the result as a string,
59 * or return `undefined` if no such macro is defined.
60 */
61 expandMacroAsText(name: string): string | void;
62
63 /**
64 * Consume the specified number of arguments from the token stream,
65 * and return the resulting array of arguments.
66 */
67 consumeArgs(numArgs: number): Token[][];
68
69 /**
70 * Determine whether a command is currently "defined" (has some
71 * functionality), meaning that it's a macro (in the current group),
72 * a function, a symbol, or one of the special commands listed in
73 * `implicitCommands`.
74 */
75 isDefined(name: string): boolean;
76}
77
78/** Macro tokens (in reverse order). */
79export type MacroExpansion = {tokens: Token[], numArgs: number};
80
81export type MacroDefinition = string | MacroExpansion |
82 (MacroContextInterface => (string | MacroExpansion));
83export type MacroMap = {[string]: MacroDefinition};
84
85const builtinMacros: MacroMap = {};
86export default builtinMacros;
87
88// This function might one day accept an additional argument and do more things.
89export function defineMacro(name: string, body: MacroDefinition) {
90 builtinMacros[name] = body;
91}
92
93//////////////////////////////////////////////////////////////////////
94// macro tools
95
96// LaTeX's \@firstoftwo{#1}{#2} expands to #1, skipping #2
97// TeX source: \long\def\@firstoftwo#1#2{#1}
98defineMacro("\\@firstoftwo", function(context) {
99 const args = context.consumeArgs(2);
100 return {tokens: args[0], numArgs: 0};
101});
102
103// LaTeX's \@secondoftwo{#1}{#2} expands to #2, skipping #1
104// TeX source: \long\def\@secondoftwo#1#2{#2}
105defineMacro("\\@secondoftwo", function(context) {
106 const args = context.consumeArgs(2);
107 return {tokens: args[1], numArgs: 0};
108});
109
110// LaTeX's \@ifnextchar{#1}{#2}{#3} looks ahead to the next (unexpanded)
111// symbol. If it matches #1, then the macro expands to #2; otherwise, #3.
112// Note, however, that it does not consume the next symbol in either case.
113defineMacro("\\@ifnextchar", function(context) {
114 const args = context.consumeArgs(3); // symbol, if, else
115 const nextToken = context.future();
116 if (args[0].length === 1 && args[0][0].text === nextToken.text) {
117 return {tokens: args[1], numArgs: 0};
118 } else {
119 return {tokens: args[2], numArgs: 0};
120 }
121});
122
123// LaTeX's \@ifstar{#1}{#2} looks ahead to the next (unexpanded) symbol.
124// If it is `*`, then it consumes the symbol, and the macro expands to #1;
125// otherwise, the macro expands to #2 (without consuming the symbol).
126// TeX source: \def\@ifstar#1{\@ifnextchar *{\@firstoftwo{#1}}}
127defineMacro("\\@ifstar", "\\@ifnextchar *{\\@firstoftwo{#1}}");
128
129// LaTeX's \TextOrMath{#1}{#2} expands to #1 in text mode, #2 in math mode
130defineMacro("\\TextOrMath", function(context) {
131 const args = context.consumeArgs(2);
132 if (context.mode === 'text') {
133 return {tokens: args[0], numArgs: 0};
134 } else {
135 return {tokens: args[1], numArgs: 0};
136 }
137});
138
139// Lookup table for parsing numbers in base 8 through 16
140const digitToNumber = {
141 "0": 0, "1": 1, "2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8": 8,
142 "9": 9, "a": 10, "A": 10, "b": 11, "B": 11, "c": 12, "C": 12,
143 "d": 13, "D": 13, "e": 14, "E": 14, "f": 15, "F": 15,
144};
145
146// TeX \char makes a literal character (catcode 12) using the following forms:
147// (see The TeXBook, p. 43)
148// \char123 -- decimal
149// \char'123 -- octal
150// \char"123 -- hex
151// \char`x -- character that can be written (i.e. isn't active)
152// \char`\x -- character that cannot be written (e.g. %)
153// These all refer to characters from the font, so we turn them into special
154// calls to a function \@char dealt with in the Parser.
155defineMacro("\\char", function(context) {
156 let token = context.popToken();
157 let base;
158 let number = '';
159 if (token.text === "'") {
160 base = 8;
161 token = context.popToken();
162 } else if (token.text === '"') {
163 base = 16;
164 token = context.popToken();
165 } else if (token.text === "`") {
166 token = context.popToken();
167 if (token.text[0] === "\\") {
168 number = token.text.charCodeAt(1);
169 } else if (token.text === "EOF") {
170 throw new ParseError("\\char` missing argument");
171 } else {
172 number = token.text.charCodeAt(0);
173 }
174 } else {
175 base = 10;
176 }
177 if (base) {
178 // Parse a number in the given base, starting with first `token`.
179 number = digitToNumber[token.text];
180 if (number == null || number >= base) {
181 throw new ParseError(`Invalid base-${base} digit ${token.text}`);
182 }
183 let digit;
184 while ((digit = digitToNumber[context.future().text]) != null &&
185 digit < base) {
186 number *= base;
187 number += digit;
188 context.popToken();
189 }
190 }
191 return `\\@char{${number}}`;
192});
193
194// Basic support for macro definitions:
195// \def\macro{expansion}
196// \def\macro#1{expansion}
197// \def\macro#1#2{expansion}
198// \def\macro#1#2#3#4#5#6#7#8#9{expansion}
199// Also the \gdef and \global\def equivalents
200const def = (context, global: boolean) => {
201 let arg = context.consumeArgs(1)[0];
202 if (arg.length !== 1) {
203 throw new ParseError("\\gdef's first argument must be a macro name");
204 }
205 const name = arg[0].text;
206 // Count argument specifiers, and check they are in the order #1 #2 ...
207 let numArgs = 0;
208 arg = context.consumeArgs(1)[0];
209 while (arg.length === 1 && arg[0].text === "#") {
210 arg = context.consumeArgs(1)[0];
211 if (arg.length !== 1) {
212 throw new ParseError(`Invalid argument number length "${arg.length}"`);
213 }
214 if (!(/^[1-9]$/.test(arg[0].text))) {
215 throw new ParseError(`Invalid argument number "${arg[0].text}"`);
216 }
217 numArgs++;
218 if (parseInt(arg[0].text) !== numArgs) {
219 throw new ParseError(`Argument number "${arg[0].text}" out of order`);
220 }
221 arg = context.consumeArgs(1)[0];
222 }
223 // Final arg is the expansion of the macro
224 context.macros.set(name, {
225 tokens: arg,
226 numArgs,
227 }, global);
228 return '';
229};
230defineMacro("\\gdef", (context) => def(context, true));
231defineMacro("\\def", (context) => def(context, false));
232defineMacro("\\global", (context) => {
233 const next = context.consumeArgs(1)[0];
234 if (next.length !== 1) {
235 throw new ParseError("Invalid command after \\global");
236 }
237 const command = next[0].text;
238 // TODO: Should expand command
239 if (command === "\\def") {
240 // \global\def is equivalent to \gdef
241 return def(context, true);
242 } else {
243 throw new ParseError(`Invalid command '${command}' after \\global`);
244 }
245});
246
247// \newcommand{\macro}[args]{definition}
248// \renewcommand{\macro}[args]{definition}
249// TODO: Optional arguments: \newcommand{\macro}[args][default]{definition}
250const newcommand = (context, existsOK: boolean, nonexistsOK: boolean) => {
251 let arg = context.consumeArgs(1)[0];
252 if (arg.length !== 1) {
253 throw new ParseError(
254 "\\newcommand's first argument must be a macro name");
255 }
256 const name = arg[0].text;
257
258 const exists = context.isDefined(name);
259 if (exists && !existsOK) {
260 throw new ParseError(`\\newcommand{${name}} attempting to redefine ` +
261 `${name}; use \\renewcommand`);
262 }
263 if (!exists && !nonexistsOK) {
264 throw new ParseError(`\\renewcommand{${name}} when command ${name} ` +
265 `does not yet exist; use \\newcommand`);
266 }
267
268 let numArgs = 0;
269 arg = context.consumeArgs(1)[0];
270 if (arg.length === 1 && arg[0].text === "[") {
271 let argText = '';
272 let token = context.expandNextToken();
273 while (token.text !== "]" && token.text !== "EOF") {
274 // TODO: Should properly expand arg, e.g., ignore {}s
275 argText += token.text;
276 token = context.expandNextToken();
277 }
278 if (!argText.match(/^\s*[0-9]+\s*$/)) {
279 throw new ParseError(`Invalid number of arguments: ${argText}`);
280 }
281 numArgs = parseInt(argText);
282 arg = context.consumeArgs(1)[0];
283 }
284
285 // Final arg is the expansion of the macro
286 context.macros.set(name, {
287 tokens: arg,
288 numArgs,
289 });
290 return '';
291};
292defineMacro("\\newcommand", (context) => newcommand(context, false, true));
293defineMacro("\\renewcommand", (context) => newcommand(context, true, false));
294defineMacro("\\providecommand", (context) => newcommand(context, true, true));
295
296//////////////////////////////////////////////////////////////////////
297// Grouping
298// \let\bgroup={ \let\egroup=}
299defineMacro("\\bgroup", "{");
300defineMacro("\\egroup", "}");
301
302// Symbols from latex.ltx:
303// \def\lq{`}
304// \def\rq{'}
305// \def \aa {\r a}
306// \def \AA {\r A}
307defineMacro("\\lq", "`");
308defineMacro("\\rq", "'");
309defineMacro("\\aa", "\\r a");
310defineMacro("\\AA", "\\r A");
311
312// Copyright (C) and registered (R) symbols. Use raw symbol in MathML.
313// \DeclareTextCommandDefault{\textcopyright}{\textcircled{c}}
314// \DeclareTextCommandDefault{\textregistered}{\textcircled{%
315// \check@mathfonts\fontsize\sf@size\z@\math@fontsfalse\selectfont R}}
316// \DeclareRobustCommand{\copyright}{%
317// \ifmmode{\nfss@text{\textcopyright}}\else\textcopyright\fi}
318defineMacro("\\textcopyright", "\\html@mathml{\\textcircled{c}}{\\char`©}");
319defineMacro("\\copyright",
320 "\\TextOrMath{\\textcopyright}{\\text{\\textcopyright}}");
321defineMacro("\\textregistered",
322 "\\html@mathml{\\textcircled{\\scriptsize R}}{\\char`®}");
323
324// Characters omitted from Unicode range 1D400–1D7FF
325defineMacro("\u212C", "\\mathscr{B}"); // script
326defineMacro("\u2130", "\\mathscr{E}");
327defineMacro("\u2131", "\\mathscr{F}");
328defineMacro("\u210B", "\\mathscr{H}");
329defineMacro("\u2110", "\\mathscr{I}");
330defineMacro("\u2112", "\\mathscr{L}");
331defineMacro("\u2133", "\\mathscr{M}");
332defineMacro("\u211B", "\\mathscr{R}");
333defineMacro("\u212D", "\\mathfrak{C}"); // Fraktur
334defineMacro("\u210C", "\\mathfrak{H}");
335defineMacro("\u2128", "\\mathfrak{Z}");
336
337// Define \Bbbk with a macro that works in both HTML and MathML.
338defineMacro("\\Bbbk", "\\Bbb{k}");
339
340// Unicode middle dot
341// The KaTeX fonts do not contain U+00B7. Instead, \cdotp displays
342// the dot at U+22C5 and gives it punct spacing.
343defineMacro("\u00b7", "\\cdotp");
344
345// \llap and \rlap render their contents in text mode
346defineMacro("\\llap", "\\mathllap{\\textrm{#1}}");
347defineMacro("\\rlap", "\\mathrlap{\\textrm{#1}}");
348defineMacro("\\clap", "\\mathclap{\\textrm{#1}}");
349
350// \not is defined by base/fontmath.ltx via
351// \DeclareMathSymbol{\not}{\mathrel}{symbols}{"36}
352// It's thus treated like a \mathrel, but defined by a symbol that has zero
353// width but extends to the right. We use \rlap to get that spacing.
354// For MathML we write U+0338 here. buildMathML.js will then do the overlay.
355defineMacro("\\not", '\\html@mathml{\\mathrel{\\mathrlap\\@not}}{\\char"338}');
356
357// Negated symbols from base/fontmath.ltx:
358// \def\neq{\not=} \let\ne=\neq
359// \DeclareRobustCommand
360// \notin{\mathrel{\m@th\mathpalette\c@ncel\in}}
361// \def\c@ncel#1#2{\m@th\ooalign{$\hfil#1\mkern1mu/\hfil$\crcr$#1#2$}}
362defineMacro("\\neq", "\\html@mathml{\\mathrel{\\not=}}{\\mathrel{\\char`≠}}");
363defineMacro("\\ne", "\\neq");
364defineMacro("\u2260", "\\neq");
365defineMacro("\\notin", "\\html@mathml{\\mathrel{{\\in}\\mathllap{/\\mskip1mu}}}"
366 + "{\\mathrel{\\char`∉}}");
367defineMacro("\u2209", "\\notin");
368
369// Unicode stacked relations
370defineMacro("\u2258", "\\html@mathml{" +
371 "\\mathrel{=\\kern{-1em}\\raisebox{0.4em}{$\\scriptsize\\frown$}}" +
372 "}{\\mathrel{\\char`\u2258}}");
373defineMacro("\u2259",
374 "\\html@mathml{\\stackrel{\\tiny\\wedge}{=}}{\\mathrel{\\char`\u2258}}");
375defineMacro("\u225A",
376 "\\html@mathml{\\stackrel{\\tiny\\vee}{=}}{\\mathrel{\\char`\u225A}}");
377defineMacro("\u225B",
378 "\\html@mathml{\\stackrel{\\scriptsize\\star}{=}}" +
379 "{\\mathrel{\\char`\u225B}}");
380defineMacro("\u225D",
381 "\\html@mathml{\\stackrel{\\tiny\\mathrm{def}}{=}}" +
382 "{\\mathrel{\\char`\u225D}}");
383defineMacro("\u225E",
384 "\\html@mathml{\\stackrel{\\tiny\\mathrm{m}}{=}}" +
385 "{\\mathrel{\\char`\u225E}}");
386defineMacro("\u225F",
387 "\\html@mathml{\\stackrel{\\tiny?}{=}}{\\mathrel{\\char`\u225F}}");
388
389// Misc Unicode
390defineMacro("\u27C2", "\\perp");
391defineMacro("\u203C", "\\mathclose{!\\mkern-0.8mu!}");
392defineMacro("\u220C", "\\notni");
393defineMacro("\u231C", "\\ulcorner");
394defineMacro("\u231D", "\\urcorner");
395defineMacro("\u231E", "\\llcorner");
396defineMacro("\u231F", "\\lrcorner");
397defineMacro("\u00A9", "\\copyright");
398defineMacro("\u00AE", "\\textregistered");
399defineMacro("\uFE0F", "\\textregistered");
400
401//////////////////////////////////////////////////////////////////////
402// LaTeX_2ε
403
404// \vdots{\vbox{\baselineskip4\p@ \lineskiplimit\z@
405// \kern6\p@\hbox{.}\hbox{.}\hbox{.}}}
406// We'll call \varvdots, which gets a glyph from symbols.js.
407// The zero-width rule gets us an equivalent to the vertical 6pt kern.
408defineMacro("\\vdots", "\\mathord{\\varvdots\\rule{0pt}{15pt}}");
409defineMacro("\u22ee", "\\vdots");
410
411//////////////////////////////////////////////////////////////////////
412// amsmath.sty
413// http://mirrors.concertpass.com/tex-archive/macros/latex/required/amsmath/amsmath.pdf
414
415// Italic Greek capital letters. AMS defines these with \DeclareMathSymbol,
416// but they are equivalent to \mathit{\Letter}.
417defineMacro("\\varGamma", "\\mathit{\\Gamma}");
418defineMacro("\\varDelta", "\\mathit{\\Delta}");
419defineMacro("\\varTheta", "\\mathit{\\Theta}");
420defineMacro("\\varLambda", "\\mathit{\\Lambda}");
421defineMacro("\\varXi", "\\mathit{\\Xi}");
422defineMacro("\\varPi", "\\mathit{\\Pi}");
423defineMacro("\\varSigma", "\\mathit{\\Sigma}");
424defineMacro("\\varUpsilon", "\\mathit{\\Upsilon}");
425defineMacro("\\varPhi", "\\mathit{\\Phi}");
426defineMacro("\\varPsi", "\\mathit{\\Psi}");
427defineMacro("\\varOmega", "\\mathit{\\Omega}");
428
429// \renewcommand{\colon}{\nobreak\mskip2mu\mathpunct{}\nonscript
430// \mkern-\thinmuskip{:}\mskip6muplus1mu\relax}
431defineMacro("\\colon", "\\nobreak\\mskip2mu\\mathpunct{}" +
432 "\\mathchoice{\\mkern-3mu}{\\mkern-3mu}{}{}{:}\\mskip6mu");
433
434// \newcommand{\boxed}[1]{\fbox{\m@th$\displaystyle#1$}}
435defineMacro("\\boxed", "\\fbox{$\\displaystyle{#1}$}");
436
437// \def\iff{\DOTSB\;\Longleftrightarrow\;}
438// \def\implies{\DOTSB\;\Longrightarrow\;}
439// \def\impliedby{\DOTSB\;\Longleftarrow\;}
440defineMacro("\\iff", "\\DOTSB\\;\\Longleftrightarrow\\;");
441defineMacro("\\implies", "\\DOTSB\\;\\Longrightarrow\\;");
442defineMacro("\\impliedby", "\\DOTSB\\;\\Longleftarrow\\;");
443
444// AMSMath's automatic \dots, based on \mdots@@ macro.
445const dotsByToken = {
446 ',': '\\dotsc',
447 '\\not': '\\dotsb',
448 // \keybin@ checks for the following:
449 '+': '\\dotsb',
450 '=': '\\dotsb',
451 '<': '\\dotsb',
452 '>': '\\dotsb',
453 '-': '\\dotsb',
454 '*': '\\dotsb',
455 ':': '\\dotsb',
456 // Symbols whose definition starts with \DOTSB:
457 '\\DOTSB': '\\dotsb',
458 '\\coprod': '\\dotsb',
459 '\\bigvee': '\\dotsb',
460 '\\bigwedge': '\\dotsb',
461 '\\biguplus': '\\dotsb',
462 '\\bigcap': '\\dotsb',
463 '\\bigcup': '\\dotsb',
464 '\\prod': '\\dotsb',
465 '\\sum': '\\dotsb',
466 '\\bigotimes': '\\dotsb',
467 '\\bigoplus': '\\dotsb',
468 '\\bigodot': '\\dotsb',
469 '\\bigsqcup': '\\dotsb',
470 '\\And': '\\dotsb',
471 '\\longrightarrow': '\\dotsb',
472 '\\Longrightarrow': '\\dotsb',
473 '\\longleftarrow': '\\dotsb',
474 '\\Longleftarrow': '\\dotsb',
475 '\\longleftrightarrow': '\\dotsb',
476 '\\Longleftrightarrow': '\\dotsb',
477 '\\mapsto': '\\dotsb',
478 '\\longmapsto': '\\dotsb',
479 '\\hookrightarrow': '\\dotsb',
480 '\\doteq': '\\dotsb',
481 // Symbols whose definition starts with \mathbin:
482 '\\mathbin': '\\dotsb',
483 // Symbols whose definition starts with \mathrel:
484 '\\mathrel': '\\dotsb',
485 '\\relbar': '\\dotsb',
486 '\\Relbar': '\\dotsb',
487 '\\xrightarrow': '\\dotsb',
488 '\\xleftarrow': '\\dotsb',
489 // Symbols whose definition starts with \DOTSI:
490 '\\DOTSI': '\\dotsi',
491 '\\int': '\\dotsi',
492 '\\oint': '\\dotsi',
493 '\\iint': '\\dotsi',
494 '\\iiint': '\\dotsi',
495 '\\iiiint': '\\dotsi',
496 '\\idotsint': '\\dotsi',
497 // Symbols whose definition starts with \DOTSX:
498 '\\DOTSX': '\\dotsx',
499};
500
501defineMacro("\\dots", function(context) {
502 // TODO: If used in text mode, should expand to \textellipsis.
503 // However, in KaTeX, \textellipsis and \ldots behave the same
504 // (in text mode), and it's unlikely we'd see any of the math commands
505 // that affect the behavior of \dots when in text mode. So fine for now
506 // (until we support \ifmmode ... \else ... \fi).
507 let thedots = '\\dotso';
508 const next = context.expandAfterFuture().text;
509 if (next in dotsByToken) {
510 thedots = dotsByToken[next];
511 } else if (next.substr(0, 4) === '\\not') {
512 thedots = '\\dotsb';
513 } else if (next in symbols.math) {
514 if (utils.contains(['bin', 'rel'], symbols.math[next].group)) {
515 thedots = '\\dotsb';
516 }
517 }
518 return thedots;
519});
520
521const spaceAfterDots = {
522 // \rightdelim@ checks for the following:
523 ')': true,
524 ']': true,
525 '\\rbrack': true,
526 '\\}': true,
527 '\\rbrace': true,
528 '\\rangle': true,
529 '\\rceil': true,
530 '\\rfloor': true,
531 '\\rgroup': true,
532 '\\rmoustache': true,
533 '\\right': true,
534 '\\bigr': true,
535 '\\biggr': true,
536 '\\Bigr': true,
537 '\\Biggr': true,
538 // \extra@ also tests for the following:
539 '$': true,
540 // \extrap@ checks for the following:
541 ';': true,
542 '.': true,
543 ',': true,
544};
545
546defineMacro("\\dotso", function(context) {
547 const next = context.future().text;
548 if (next in spaceAfterDots) {
549 return "\\ldots\\,";
550 } else {
551 return "\\ldots";
552 }
553});
554
555defineMacro("\\dotsc", function(context) {
556 const next = context.future().text;
557 // \dotsc uses \extra@ but not \extrap@, instead specially checking for
558 // ';' and '.', but doesn't check for ','.
559 if (next in spaceAfterDots && next !== ',') {
560 return "\\ldots\\,";
561 } else {
562 return "\\ldots";
563 }
564});
565
566defineMacro("\\cdots", function(context) {
567 const next = context.future().text;
568 if (next in spaceAfterDots) {
569 return "\\@cdots\\,";
570 } else {
571 return "\\@cdots";
572 }
573});
574
575defineMacro("\\dotsb", "\\cdots");
576defineMacro("\\dotsm", "\\cdots");
577defineMacro("\\dotsi", "\\!\\cdots");
578// amsmath doesn't actually define \dotsx, but \dots followed by a macro
579// starting with \DOTSX implies \dotso, and then \extra@ detects this case
580// and forces the added `\,`.
581defineMacro("\\dotsx", "\\ldots\\,");
582
583// \let\DOTSI\relax
584// \let\DOTSB\relax
585// \let\DOTSX\relax
586defineMacro("\\DOTSI", "\\relax");
587defineMacro("\\DOTSB", "\\relax");
588defineMacro("\\DOTSX", "\\relax");
589
590// Spacing, based on amsmath.sty's override of LaTeX defaults
591// \DeclareRobustCommand{\tmspace}[3]{%
592// \ifmmode\mskip#1#2\else\kern#1#3\fi\relax}
593defineMacro("\\tmspace", "\\TextOrMath{\\kern#1#3}{\\mskip#1#2}\\relax");
594// \renewcommand{\,}{\tmspace+\thinmuskip{.1667em}}
595// TODO: math mode should use \thinmuskip
596defineMacro("\\,", "\\tmspace+{3mu}{.1667em}");
597// \let\thinspace\,
598defineMacro("\\thinspace", "\\,");
599// \def\>{\mskip\medmuskip}
600// \renewcommand{\:}{\tmspace+\medmuskip{.2222em}}
601// TODO: \> and math mode of \: should use \medmuskip = 4mu plus 2mu minus 4mu
602defineMacro("\\>", "\\mskip{4mu}");
603defineMacro("\\:", "\\tmspace+{4mu}{.2222em}");
604// \let\medspace\:
605defineMacro("\\medspace", "\\:");
606// \renewcommand{\;}{\tmspace+\thickmuskip{.2777em}}
607// TODO: math mode should use \thickmuskip = 5mu plus 5mu
608defineMacro("\\;", "\\tmspace+{5mu}{.2777em}");
609// \let\thickspace\;
610defineMacro("\\thickspace", "\\;");
611// \renewcommand{\!}{\tmspace-\thinmuskip{.1667em}}
612// TODO: math mode should use \thinmuskip
613defineMacro("\\!", "\\tmspace-{3mu}{.1667em}");
614// \let\negthinspace\!
615defineMacro("\\negthinspace", "\\!");
616// \newcommand{\negmedspace}{\tmspace-\medmuskip{.2222em}}
617// TODO: math mode should use \medmuskip
618defineMacro("\\negmedspace", "\\tmspace-{4mu}{.2222em}");
619// \newcommand{\negthickspace}{\tmspace-\thickmuskip{.2777em}}
620// TODO: math mode should use \thickmuskip
621defineMacro("\\negthickspace", "\\tmspace-{5mu}{.277em}");
622// \def\enspace{\kern.5em }
623defineMacro("\\enspace", "\\kern.5em ");
624// \def\enskip{\hskip.5em\relax}
625defineMacro("\\enskip", "\\hskip.5em\\relax");
626// \def\quad{\hskip1em\relax}
627defineMacro("\\quad", "\\hskip1em\\relax");
628// \def\qquad{\hskip2em\relax}
629defineMacro("\\qquad", "\\hskip2em\\relax");
630
631// \tag@in@display form of \tag
632defineMacro("\\tag", "\\@ifstar\\tag@literal\\tag@paren");
633defineMacro("\\tag@paren", "\\tag@literal{({#1})}");
634defineMacro("\\tag@literal", (context) => {
635 if (context.macros.get("\\df@tag")) {
636 throw new ParseError("Multiple \\tag");
637 }
638 return "\\gdef\\df@tag{\\text{#1}}";
639});
640
641// \renewcommand{\bmod}{\nonscript\mskip-\medmuskip\mkern5mu\mathbin
642// {\operator@font mod}\penalty900
643// \mkern5mu\nonscript\mskip-\medmuskip}
644// \newcommand{\pod}[1]{\allowbreak
645// \if@display\mkern18mu\else\mkern8mu\fi(#1)}
646// \renewcommand{\pmod}[1]{\pod{{\operator@font mod}\mkern6mu#1}}
647// \newcommand{\mod}[1]{\allowbreak\if@display\mkern18mu
648// \else\mkern12mu\fi{\operator@font mod}\,\,#1}
649// TODO: math mode should use \medmuskip = 4mu plus 2mu minus 4mu
650defineMacro("\\bmod",
651 "\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}" +
652 "\\mathbin{\\rm mod}" +
653 "\\mathchoice{\\mskip1mu}{\\mskip1mu}{\\mskip5mu}{\\mskip5mu}");
654defineMacro("\\pod", "\\allowbreak" +
655 "\\mathchoice{\\mkern18mu}{\\mkern8mu}{\\mkern8mu}{\\mkern8mu}(#1)");
656defineMacro("\\pmod", "\\pod{{\\rm mod}\\mkern6mu#1}");
657defineMacro("\\mod", "\\allowbreak" +
658 "\\mathchoice{\\mkern18mu}{\\mkern12mu}{\\mkern12mu}{\\mkern12mu}" +
659 "{\\rm mod}\\,\\,#1");
660
661// \pmb -- A simulation of bold.
662// It works by typesetting three copies of the argument with small offsets.
663// Ref: a rather lengthy macro in ambsy.sty
664defineMacro("\\pmb", "\\html@mathml{\\@binrel{#1}{" +
665 "\\mathrlap{#1}" +
666 "\\mathrlap{\\mkern0.4mu\\raisebox{0.4mu}{$#1$}}" +
667 "{\\mkern0.8mu#1}" +
668 "}}{\\mathbf{#1}}");
669
670//////////////////////////////////////////////////////////////////////
671// LaTeX source2e
672
673// \\ defaults to \newline, but changes to \cr within array environment
674defineMacro("\\\\", "\\newline");
675
676// \def\TeX{T\kern-.1667em\lower.5ex\hbox{E}\kern-.125emX\@}
677// TODO: Doesn't normally work in math mode because \@ fails. KaTeX doesn't
678// support \@ yet, so that's omitted, and we add \text so that the result
679// doesn't look funny in math mode.
680defineMacro("\\TeX", "\\textrm{\\html@mathml{" +
681 "T\\kern-.1667em\\raisebox{-.5ex}{E}\\kern-.125emX" +
682 "}{TeX}}");
683
684// \DeclareRobustCommand{\LaTeX}{L\kern-.36em%
685// {\sbox\z@ T%
686// \vbox to\ht\z@{\hbox{\check@mathfonts
687// \fontsize\sf@size\z@
688// \math@fontsfalse\selectfont
689// A}%
690// \vss}%
691// }%
692// \kern-.15em%
693// \TeX}
694// This code aligns the top of the A with the T (from the perspective of TeX's
695// boxes, though visually the A appears to extend above slightly).
696// We compute the corresponding \raisebox when A is rendered at \scriptsize,
697// which is size3, which has a scale factor of 0.7 (see Options.js).
698const latexRaiseA = fontMetricsData['Main-Regular']["T".charCodeAt(0)][1] -
699 0.7 * fontMetricsData['Main-Regular']["A".charCodeAt(0)][1] + "em";
700defineMacro("\\LaTeX", "\\textrm{\\html@mathml{" +
701 `L\\kern-.36em\\raisebox{${latexRaiseA}}{\\scriptsize A}` +
702 "\\kern-.15em\\TeX}{LaTeX}}");
703
704// New KaTeX logo based on tweaking LaTeX logo
705defineMacro("\\KaTeX", "\\textrm{\\html@mathml{" +
706 `K\\kern-.17em\\raisebox{${latexRaiseA}}{\\scriptsize A}` +
707 "\\kern-.15em\\TeX}{KaTeX}}");
708
709// \DeclareRobustCommand\hspace{\@ifstar\@hspacer\@hspace}
710// \def\@hspace#1{\hskip #1\relax}
711// \def\@hspacer#1{\vrule \@width\z@\nobreak
712// \hskip #1\hskip \z@skip}
713defineMacro("\\hspace", "\\@ifstar\\@hspacer\\@hspace");
714defineMacro("\\@hspace", "\\hskip #1\\relax");
715defineMacro("\\@hspacer", "\\rule{0pt}{0pt}\\hskip #1\\relax");
716
717//////////////////////////////////////////////////////////////////////
718// mathtools.sty
719
720//\providecommand\ordinarycolon{:}
721defineMacro("\\ordinarycolon", ":");
722//\def\vcentcolon{\mathrel{\mathop\ordinarycolon}}
723//TODO(edemaine): Not yet centered. Fix via \raisebox or #726
724defineMacro("\\vcentcolon", "\\mathrel{\\mathop\\ordinarycolon}");
725// \providecommand*\dblcolon{\vcentcolon\mathrel{\mkern-.9mu}\vcentcolon}
726defineMacro("\\dblcolon", "\\html@mathml{" +
727 "\\mathrel{\\vcentcolon\\mathrel{\\mkern-.9mu}\\vcentcolon}}" +
728 "{\\mathop{\\char\"2237}}");
729// \providecommand*\coloneqq{\vcentcolon\mathrel{\mkern-1.2mu}=}
730defineMacro("\\coloneqq", "\\html@mathml{" +
731 "\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}=}}" +
732 "{\\mathop{\\char\"2254}}"); // ≔
733// \providecommand*\Coloneqq{\dblcolon\mathrel{\mkern-1.2mu}=}
734defineMacro("\\Coloneqq", "\\html@mathml{" +
735 "\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}=}}" +
736 "{\\mathop{\\char\"2237\\char\"3d}}");
737// \providecommand*\coloneq{\vcentcolon\mathrel{\mkern-1.2mu}\mathrel{-}}
738defineMacro("\\coloneq", "\\html@mathml{" +
739 "\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}" +
740 "{\\mathop{\\char\"3a\\char\"2212}}");
741// \providecommand*\Coloneq{\dblcolon\mathrel{\mkern-1.2mu}\mathrel{-}}
742defineMacro("\\Coloneq", "\\html@mathml{" +
743 "\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\mathrel{-}}}" +
744 "{\\mathop{\\char\"2237\\char\"2212}}");
745// \providecommand*\eqqcolon{=\mathrel{\mkern-1.2mu}\vcentcolon}
746defineMacro("\\eqqcolon", "\\html@mathml{" +
747 "\\mathrel{=\\mathrel{\\mkern-1.2mu}\\vcentcolon}}" +
748 "{\\mathop{\\char\"2255}}"); // ≕
749// \providecommand*\Eqqcolon{=\mathrel{\mkern-1.2mu}\dblcolon}
750defineMacro("\\Eqqcolon", "\\html@mathml{" +
751 "\\mathrel{=\\mathrel{\\mkern-1.2mu}\\dblcolon}}" +
752 "{\\mathop{\\char\"3d\\char\"2237}}");
753// \providecommand*\eqcolon{\mathrel{-}\mathrel{\mkern-1.2mu}\vcentcolon}
754defineMacro("\\eqcolon", "\\html@mathml{" +
755 "\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\vcentcolon}}" +
756 "{\\mathop{\\char\"2239}}");
757// \providecommand*\Eqcolon{\mathrel{-}\mathrel{\mkern-1.2mu}\dblcolon}
758defineMacro("\\Eqcolon", "\\html@mathml{" +
759 "\\mathrel{\\mathrel{-}\\mathrel{\\mkern-1.2mu}\\dblcolon}}" +
760 "{\\mathop{\\char\"2212\\char\"2237}}");
761// \providecommand*\colonapprox{\vcentcolon\mathrel{\mkern-1.2mu}\approx}
762defineMacro("\\colonapprox", "\\html@mathml{" +
763 "\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\approx}}" +
764 "{\\mathop{\\char\"3a\\char\"2248}}");
765// \providecommand*\Colonapprox{\dblcolon\mathrel{\mkern-1.2mu}\approx}
766defineMacro("\\Colonapprox", "\\html@mathml{" +
767 "\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\approx}}" +
768 "{\\mathop{\\char\"2237\\char\"2248}}");
769// \providecommand*\colonsim{\vcentcolon\mathrel{\mkern-1.2mu}\sim}
770defineMacro("\\colonsim", "\\html@mathml{" +
771 "\\mathrel{\\vcentcolon\\mathrel{\\mkern-1.2mu}\\sim}}" +
772 "{\\mathop{\\char\"3a\\char\"223c}}");
773// \providecommand*\Colonsim{\dblcolon\mathrel{\mkern-1.2mu}\sim}
774defineMacro("\\Colonsim", "\\html@mathml{" +
775 "\\mathrel{\\dblcolon\\mathrel{\\mkern-1.2mu}\\sim}}" +
776 "{\\mathop{\\char\"2237\\char\"223c}}");
777
778// Some Unicode characters are implemented with macros to mathtools functions.
779defineMacro("\u2237", "\\dblcolon"); // ::
780defineMacro("\u2239", "\\eqcolon"); // -:
781defineMacro("\u2254", "\\coloneqq"); // :=
782defineMacro("\u2255", "\\eqqcolon"); // =:
783defineMacro("\u2A74", "\\Coloneqq"); // ::=
784
785//////////////////////////////////////////////////////////////////////
786// colonequals.sty
787
788// Alternate names for mathtools's macros:
789defineMacro("\\ratio", "\\vcentcolon");
790defineMacro("\\coloncolon", "\\dblcolon");
791defineMacro("\\colonequals", "\\coloneqq");
792defineMacro("\\coloncolonequals", "\\Coloneqq");
793defineMacro("\\equalscolon", "\\eqqcolon");
794defineMacro("\\equalscoloncolon", "\\Eqqcolon");
795defineMacro("\\colonminus", "\\coloneq");
796defineMacro("\\coloncolonminus", "\\Coloneq");
797defineMacro("\\minuscolon", "\\eqcolon");
798defineMacro("\\minuscoloncolon", "\\Eqcolon");
799// \colonapprox name is same in mathtools and colonequals.
800defineMacro("\\coloncolonapprox", "\\Colonapprox");
801// \colonsim name is same in mathtools and colonequals.
802defineMacro("\\coloncolonsim", "\\Colonsim");
803
804// Additional macros, implemented by analogy with mathtools definitions:
805defineMacro("\\simcolon",
806 "\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\vcentcolon}");
807defineMacro("\\simcoloncolon",
808 "\\mathrel{\\sim\\mathrel{\\mkern-1.2mu}\\dblcolon}");
809defineMacro("\\approxcolon",
810 "\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\vcentcolon}");
811defineMacro("\\approxcoloncolon",
812 "\\mathrel{\\approx\\mathrel{\\mkern-1.2mu}\\dblcolon}");
813
814// Present in newtxmath, pxfonts and txfonts
815defineMacro("\\notni", "\\html@mathml{\\not\\ni}{\\mathrel{\\char`\u220C}}");
816defineMacro("\\limsup", "\\DOTSB\\mathop{\\operatorname{lim\\,sup}}\\limits");
817defineMacro("\\liminf", "\\DOTSB\\mathop{\\operatorname{lim\\,inf}}\\limits");
818
819//////////////////////////////////////////////////////////////////////
820// MathML alternates for KaTeX glyphs in the Unicode private area
821defineMacro("\\gvertneqq", "\\html@mathml{\\@gvertneqq}{\u2269}");
822defineMacro("\\lvertneqq", "\\html@mathml{\\@lvertneqq}{\u2268}");
823defineMacro("\\ngeqq", "\\html@mathml{\\@ngeqq}{\u2271}");
824defineMacro("\\ngeqslant", "\\html@mathml{\\@ngeqslant}{\u2271}");
825defineMacro("\\nleqq", "\\html@mathml{\\@nleqq}{\u2270}");
826defineMacro("\\nleqslant", "\\html@mathml{\\@nleqslant}{\u2270}");
827defineMacro("\\nshortmid", "\\html@mathml{\\@nshortmid}{∤}");
828defineMacro("\\nshortparallel", "\\html@mathml{\\@nshortparallel}{∦}");
829defineMacro("\\nsubseteqq", "\\html@mathml{\\@nsubseteqq}{\u2288}");
830defineMacro("\\nsupseteqq", "\\html@mathml{\\@nsupseteqq}{\u2289}");
831defineMacro("\\varsubsetneq", "\\html@mathml{\\@varsubsetneq}{⊊}");
832defineMacro("\\varsubsetneqq", "\\html@mathml{\\@varsubsetneqq}{⫋}");
833defineMacro("\\varsupsetneq", "\\html@mathml{\\@varsupsetneq}{⊋}");
834defineMacro("\\varsupsetneqq", "\\html@mathml{\\@varsupsetneqq}{⫌}");
835
836//////////////////////////////////////////////////////////////////////
837// stmaryrd and semantic
838
839// The stmaryrd and semantic packages render the next four items by calling a
840// glyph. Those glyphs do not exist in the KaTeX fonts. Hence the macros.
841
842defineMacro("\\llbracket", "\\html@mathml{" +
843 "\\mathopen{[\\mkern-3.2mu[}}" +
844 "{\\mathopen{\\char`\u27e6}}");
845defineMacro("\\rrbracket", "\\html@mathml{" +
846 "\\mathclose{]\\mkern-3.2mu]}}" +
847 "{\\mathclose{\\char`\u27e7}}");
848
849defineMacro("\u27e6", "\\llbracket"); // blackboard bold [
850defineMacro("\u27e7", "\\rrbracket"); // blackboard bold ]
851
852defineMacro("\\lBrace", "\\html@mathml{" +
853 "\\mathopen{\\{\\mkern-3.2mu[}}" +
854 "{\\mathopen{\\char`\u2983}}");
855defineMacro("\\rBrace", "\\html@mathml{" +
856 "\\mathclose{]\\mkern-3.2mu\\}}}" +
857 "{\\mathclose{\\char`\u2984}}");
858
859defineMacro("\u2983", "\\lBrace"); // blackboard bold {
860defineMacro("\u2984", "\\rBrace"); // blackboard bold }
861
862// TODO: Create variable sized versions of the last two items. I believe that
863// will require new font glyphs.
864
865//////////////////////////////////////////////////////////////////////
866// texvc.sty
867
868// The texvc package contains macros available in mediawiki pages.
869// We omit the functions deprecated at
870// https://en.wikipedia.org/wiki/Help:Displaying_a_formula#Deprecated_syntax
871
872// We also omit texvc's \O, which conflicts with \text{\O}
873
874defineMacro("\\darr", "\\downarrow");
875defineMacro("\\dArr", "\\Downarrow");
876defineMacro("\\Darr", "\\Downarrow");
877defineMacro("\\lang", "\\langle");
878defineMacro("\\rang", "\\rangle");
879defineMacro("\\uarr", "\\uparrow");
880defineMacro("\\uArr", "\\Uparrow");
881defineMacro("\\Uarr", "\\Uparrow");
882defineMacro("\\N", "\\mathbb{N}");
883defineMacro("\\R", "\\mathbb{R}");
884defineMacro("\\Z", "\\mathbb{Z}");
885defineMacro("\\alef", "\\aleph");
886defineMacro("\\alefsym", "\\aleph");
887defineMacro("\\Alpha", "\\mathrm{A}");
888defineMacro("\\Beta", "\\mathrm{B}");
889defineMacro("\\bull", "\\bullet");
890defineMacro("\\Chi", "\\mathrm{X}");
891defineMacro("\\clubs", "\\clubsuit");
892defineMacro("\\cnums", "\\mathbb{C}");
893defineMacro("\\Complex", "\\mathbb{C}");
894defineMacro("\\Dagger", "\\ddagger");
895defineMacro("\\diamonds", "\\diamondsuit");
896defineMacro("\\empty", "\\emptyset");
897defineMacro("\\Epsilon", "\\mathrm{E}");
898defineMacro("\\Eta", "\\mathrm{H}");
899defineMacro("\\exist", "\\exists");
900defineMacro("\\harr", "\\leftrightarrow");
901defineMacro("\\hArr", "\\Leftrightarrow");
902defineMacro("\\Harr", "\\Leftrightarrow");
903defineMacro("\\hearts", "\\heartsuit");
904defineMacro("\\image", "\\Im");
905defineMacro("\\infin", "\\infty");
906defineMacro("\\Iota", "\\mathrm{I}");
907defineMacro("\\isin", "\\in");
908defineMacro("\\Kappa", "\\mathrm{K}");
909defineMacro("\\larr", "\\leftarrow");
910defineMacro("\\lArr", "\\Leftarrow");
911defineMacro("\\Larr", "\\Leftarrow");
912defineMacro("\\lrarr", "\\leftrightarrow");
913defineMacro("\\lrArr", "\\Leftrightarrow");
914defineMacro("\\Lrarr", "\\Leftrightarrow");
915defineMacro("\\Mu", "\\mathrm{M}");
916defineMacro("\\natnums", "\\mathbb{N}");
917defineMacro("\\Nu", "\\mathrm{N}");
918defineMacro("\\Omicron", "\\mathrm{O}");
919defineMacro("\\plusmn", "\\pm");
920defineMacro("\\rarr", "\\rightarrow");
921defineMacro("\\rArr", "\\Rightarrow");
922defineMacro("\\Rarr", "\\Rightarrow");
923defineMacro("\\real", "\\Re");
924defineMacro("\\reals", "\\mathbb{R}");
925defineMacro("\\Reals", "\\mathbb{R}");
926defineMacro("\\Rho", "\\mathrm{P}");
927defineMacro("\\sdot", "\\cdot");
928defineMacro("\\sect", "\\S");
929defineMacro("\\spades", "\\spadesuit");
930defineMacro("\\sub", "\\subset");
931defineMacro("\\sube", "\\subseteq");
932defineMacro("\\supe", "\\supseteq");
933defineMacro("\\Tau", "\\mathrm{T}");
934defineMacro("\\thetasym", "\\vartheta");
935// TODO: defineMacro("\\varcoppa", "\\\mbox{\\coppa}");
936defineMacro("\\weierp", "\\wp");
937defineMacro("\\Zeta", "\\mathrm{Z}");
938
939//////////////////////////////////////////////////////////////////////
940// statmath.sty
941// https://ctan.math.illinois.edu/macros/latex/contrib/statmath/statmath.pdf
942
943defineMacro("\\argmin", "\\DOTSB\\mathop{\\operatorname{arg\\,min}}\\limits");
944defineMacro("\\argmax", "\\DOTSB\\mathop{\\operatorname{arg\\,max}}\\limits");
945
946// Custom Khan Academy colors, should be moved to an optional package
947defineMacro("\\blue", "\\textcolor{##6495ed}{#1}");
948defineMacro("\\orange", "\\textcolor{##ffa500}{#1}");
949defineMacro("\\pink", "\\textcolor{##ff00af}{#1}");
950defineMacro("\\red", "\\textcolor{##df0030}{#1}");
951defineMacro("\\green", "\\textcolor{##28ae7b}{#1}");
952defineMacro("\\gray", "\\textcolor{gray}{##1}");
953defineMacro("\\purple", "\\textcolor{##9d38bd}{#1}");
954defineMacro("\\blueA", "\\textcolor{##ccfaff}{#1}");
955defineMacro("\\blueB", "\\textcolor{##80f6ff}{#1}");
956defineMacro("\\blueC", "\\textcolor{##63d9ea}{#1}");
957defineMacro("\\blueD", "\\textcolor{##11accd}{#1}");
958defineMacro("\\blueE", "\\textcolor{##0c7f99}{#1}");
959defineMacro("\\tealA", "\\textcolor{##94fff5}{#1}");
960defineMacro("\\tealB", "\\textcolor{##26edd5}{#1}");
961defineMacro("\\tealC", "\\textcolor{##01d1c1}{#1}");
962defineMacro("\\tealD", "\\textcolor{##01a995}{#1}");
963defineMacro("\\tealE", "\\textcolor{##208170}{#1}");
964defineMacro("\\greenA", "\\textcolor{##b6ffb0}{#1}");
965defineMacro("\\greenB", "\\textcolor{##8af281}{#1}");
966defineMacro("\\greenC", "\\textcolor{##74cf70}{#1}");
967defineMacro("\\greenD", "\\textcolor{##1fab54}{#1}");
968defineMacro("\\greenE", "\\textcolor{##0d923f}{#1}");
969defineMacro("\\goldA", "\\textcolor{##ffd0a9}{#1}");
970defineMacro("\\goldB", "\\textcolor{##ffbb71}{#1}");
971defineMacro("\\goldC", "\\textcolor{##ff9c39}{#1}");
972defineMacro("\\goldD", "\\textcolor{##e07d10}{#1}");
973defineMacro("\\goldE", "\\textcolor{##a75a05}{#1}");
974defineMacro("\\redA", "\\textcolor{##fca9a9}{#1}");
975defineMacro("\\redB", "\\textcolor{##ff8482}{#1}");
976defineMacro("\\redC", "\\textcolor{##f9685d}{#1}");
977defineMacro("\\redD", "\\textcolor{##e84d39}{#1}");
978defineMacro("\\redE", "\\textcolor{##bc2612}{#1}");
979defineMacro("\\maroonA", "\\textcolor{##ffbde0}{#1}");
980defineMacro("\\maroonB", "\\textcolor{##ff92c6}{#1}");
981defineMacro("\\maroonC", "\\textcolor{##ed5fa6}{#1}");
982defineMacro("\\maroonD", "\\textcolor{##ca337c}{#1}");
983defineMacro("\\maroonE", "\\textcolor{##9e034e}{#1}");
984defineMacro("\\purpleA", "\\textcolor{##ddd7ff}{#1}");
985defineMacro("\\purpleB", "\\textcolor{##c6b9fc}{#1}");
986defineMacro("\\purpleC", "\\textcolor{##aa87ff}{#1}");
987defineMacro("\\purpleD", "\\textcolor{##7854ab}{#1}");
988defineMacro("\\purpleE", "\\textcolor{##543b78}{#1}");
989defineMacro("\\mintA", "\\textcolor{##f5f9e8}{#1}");
990defineMacro("\\mintB", "\\textcolor{##edf2df}{#1}");
991defineMacro("\\mintC", "\\textcolor{##e0e5cc}{#1}");
992defineMacro("\\grayA", "\\textcolor{##f6f7f7}{#1}");
993defineMacro("\\grayB", "\\textcolor{##f0f1f2}{#1}");
994defineMacro("\\grayC", "\\textcolor{##e3e5e6}{#1}");
995defineMacro("\\grayD", "\\textcolor{##d6d8da}{#1}");
996defineMacro("\\grayE", "\\textcolor{##babec2}{#1}");
997defineMacro("\\grayF", "\\textcolor{##888d93}{#1}");
998defineMacro("\\grayG", "\\textcolor{##626569}{#1}");
999defineMacro("\\grayH", "\\textcolor{##3b3e40}{#1}");
1000defineMacro("\\grayI", "\\textcolor{##21242c}{#1}");
1001defineMacro("\\kaBlue", "\\textcolor{##314453}{#1}");
1002defineMacro("\\kaGreen", "\\textcolor{##71B307}{#1}");