mirror of
https://github.com/Smaug123/KaTeX
synced 2025-10-05 03:08:40 +00:00
refactor: separate defineMacro.js from macros.js (#3198)
Allows defineMacro to be called from other places, in particular removing cycles from the dependency graph.
This commit is contained in:
@@ -15,7 +15,7 @@ You can provide an object of options as the last argument to [`katex.render` and
|
||||
- `fleqn`: `boolean`. If `true`, display math renders flush left with a `2em` left margin, like `\documentclass[fleqn]` in LaTeX with the `amsmath` package.
|
||||
- `throwOnError`: `boolean`. If `true` (the default), KaTeX will throw a `ParseError` when it encounters an unsupported command or invalid LaTeX. If `false`, KaTeX will render unsupported commands as text, and render invalid LaTeX as its source code with hover text giving the error, in the color given by `errorColor`.
|
||||
- `errorColor`: `string`. A color string given in the format `"#XXX"` or `"#XXXXXX"`. This option determines the color that unsupported commands and invalid LaTeX are rendered in when `throwOnError` is set to `false`. (default: `#cc0000`)
|
||||
- `macros`: `object`. A collection of custom macros. Each macro is a property with a name like `\name` (written `"\\name"` in JavaScript) which maps to a string that describes the expansion of the macro, or a function that accepts an instance of `MacroExpander` as first argument and returns the expansion as a string. `MacroExpander` is an internal API and subject to non-backwards compatible changes. See [`src/macros.js`](https://github.com/KaTeX/KaTeX/blob/master/src/macros.js) for its usage. Single-character keys can also be included in which case the character will be redefined as the given macro (similar to TeX active characters). *This object will be modified* if the LaTeX code defines its own macros via `\gdef`, which enables consecutive calls to KaTeX to share state.
|
||||
- `macros`: `object`. A collection of custom macros. Each macro is a property with a name like `\name` (written `"\\name"` in JavaScript) which maps to a string that describes the expansion of the macro, or a function that accepts an instance of `MacroExpander` as first argument and returns the expansion as a string. `MacroExpander` is an internal API and subject to non-backwards compatible changes. See [`src/defineMacro.js`](https://github.com/KaTeX/KaTeX/blob/master/src/defineMacro.js) for its usage. Single-character keys can also be included in which case the character will be redefined as the given macro (similar to TeX active characters). *This object will be modified* if the LaTeX code defines its own macros via `\gdef`, which enables consecutive calls to KaTeX to share state.
|
||||
- `minRuleThickness`: `number`. Specifies a minimum thickness, in ems, for fraction lines, `\sqrt` top lines, `{array}` vertical lines, `\hline`, `\hdashline`, `\underline`, `\overline`, and the borders of `\fbox`, `\boxed`, and `\fcolorbox`. The usual value for these items is `0.04`, so for `minRuleThickness` to be effective it should probably take a value slightly above `0.04`, say `0.05` or `0.06`. Negative values will be ignored.
|
||||
- `colorIsTextColor`: `boolean`. In early versions of both KaTeX (<0.8.0) and MathJax, the `\color` function expected the content to be a function argument, as in `\color{blue}{hello}`. In current KaTeX, `\color` is a switch, as in `\color{blue} hello`. This matches LaTeX behavior. If you want the old `\color` behavior, set option `colorIsTextColor` to true.
|
||||
- `maxSize`: `number`. All user-specified sizes, e.g. in `\rule{500em}{500em}`, will be capped to `maxSize` ems. If set to `Infinity` (the default), users can make elements and spaces arbitrarily large.
|
||||
|
2
katex.js
2
katex.js
@@ -28,7 +28,7 @@ import type {AnyParseNode} from "./src/parseNode";
|
||||
import type {DomSpan} from "./src/domTree";
|
||||
|
||||
import {defineSymbol} from './src/symbols';
|
||||
import {defineMacro} from './src/macros';
|
||||
import defineMacro from './src/defineMacro';
|
||||
import {setFontMetrics} from './src/fontMetrics';
|
||||
|
||||
declare var __VERSION__: string;
|
||||
|
@@ -11,10 +11,10 @@ import {Token} from "./Token";
|
||||
import type {Mode} from "./types";
|
||||
import ParseError from "./ParseError";
|
||||
import Namespace from "./Namespace";
|
||||
import builtinMacros from "./macros";
|
||||
import macros from "./macros";
|
||||
|
||||
import type {MacroContextInterface, MacroDefinition, MacroExpansion, MacroArg}
|
||||
from "./macros";
|
||||
from "./defineMacro";
|
||||
import type Settings from "./Settings";
|
||||
|
||||
// List of commands that act like macros but aren't defined as a macro,
|
||||
@@ -40,7 +40,7 @@ export default class MacroExpander implements MacroContextInterface {
|
||||
this.expansionCount = 0;
|
||||
this.feed(input);
|
||||
// Make new global namespace
|
||||
this.macros = new Namespace(builtinMacros, settings.macros);
|
||||
this.macros = new Namespace(macros, settings.macros);
|
||||
this.mode = mode;
|
||||
this.stack = []; // contains tokens in REVERSE order
|
||||
}
|
||||
|
@@ -10,7 +10,7 @@ import ParseError from "./ParseError";
|
||||
import {Token} from "./Token";
|
||||
|
||||
import type {AnyParseNode} from "./parseNode";
|
||||
import type {MacroMap} from "./macros";
|
||||
import type {MacroMap} from "./defineMacro";
|
||||
|
||||
export type StrictFunction =
|
||||
(errorCode: string, errorMsg: string, token?: Token | AnyParseNode) =>
|
||||
|
118
src/defineMacro.js
Normal file
118
src/defineMacro.js
Normal file
@@ -0,0 +1,118 @@
|
||||
// @flow
|
||||
|
||||
import {Token} from "./Token";
|
||||
import type Namespace from "./Namespace";
|
||||
import type {Mode} from "./types";
|
||||
|
||||
/**
|
||||
* Provides context to macros defined by functions. Implemented by
|
||||
* MacroExpander.
|
||||
*/
|
||||
export interface MacroContextInterface {
|
||||
mode: Mode;
|
||||
|
||||
/**
|
||||
* Object mapping macros to their expansions.
|
||||
*/
|
||||
macros: Namespace<MacroDefinition>;
|
||||
|
||||
/**
|
||||
* Returns the topmost token on the stack, without expanding it.
|
||||
* Similar in behavior to TeX's `\futurelet`.
|
||||
*/
|
||||
future(): Token;
|
||||
|
||||
/**
|
||||
* Remove and return the next unexpanded token.
|
||||
*/
|
||||
popToken(): Token;
|
||||
|
||||
/**
|
||||
* Consume all following space tokens, without expansion.
|
||||
*/
|
||||
consumeSpaces(): void;
|
||||
|
||||
/**
|
||||
* Expand the next token only once if possible.
|
||||
*/
|
||||
expandOnce(expandableOnly?: boolean): Token | Token[];
|
||||
|
||||
/**
|
||||
* Expand the next token only once (if possible), and return the resulting
|
||||
* top token on the stack (without removing anything from the stack).
|
||||
* Similar in behavior to TeX's `\expandafter\futurelet`.
|
||||
*/
|
||||
expandAfterFuture(): Token;
|
||||
|
||||
/**
|
||||
* Recursively expand first token, then return first non-expandable token.
|
||||
*/
|
||||
expandNextToken(): Token;
|
||||
|
||||
/**
|
||||
* Fully expand the given macro name and return the resulting list of
|
||||
* tokens, or return `undefined` if no such macro is defined.
|
||||
*/
|
||||
expandMacro(name: string): Token[] | void;
|
||||
|
||||
/**
|
||||
* Fully expand the given macro name and return the result as a string,
|
||||
* or return `undefined` if no such macro is defined.
|
||||
*/
|
||||
expandMacroAsText(name: string): string | void;
|
||||
|
||||
/**
|
||||
* Consume an argument from the token stream, and return the resulting array
|
||||
* of tokens and start/end token.
|
||||
*/
|
||||
consumeArg(delims?: ?string[]): MacroArg;
|
||||
|
||||
/**
|
||||
* Consume the specified number of arguments from the token stream,
|
||||
* and return the resulting array of arguments.
|
||||
*/
|
||||
consumeArgs(numArgs: number): Token[][];
|
||||
|
||||
/**
|
||||
* Determine whether a command is currently "defined" (has some
|
||||
* functionality), meaning that it's a macro (in the current group),
|
||||
* a function, a symbol, or one of the special commands listed in
|
||||
* `implicitCommands`.
|
||||
*/
|
||||
isDefined(name: string): boolean;
|
||||
|
||||
/**
|
||||
* Determine whether a command is expandable.
|
||||
*/
|
||||
isExpandable(name: string): boolean;
|
||||
}
|
||||
|
||||
export type MacroArg = {
|
||||
tokens: Token[],
|
||||
start: Token,
|
||||
end: Token
|
||||
};
|
||||
|
||||
/** Macro tokens (in reverse order). */
|
||||
export type MacroExpansion = {
|
||||
tokens: Token[],
|
||||
numArgs: number,
|
||||
delimiters?: string[][],
|
||||
unexpandable?: boolean, // used in \let
|
||||
};
|
||||
|
||||
export type MacroDefinition = string | MacroExpansion |
|
||||
(MacroContextInterface => (string | MacroExpansion));
|
||||
export type MacroMap = {[string]: MacroDefinition};
|
||||
|
||||
/**
|
||||
* All registered global/built-in macros.
|
||||
* `macros.js` exports this same dictionary again and makes it public.
|
||||
* `Parser.js` requires this dictionary via `macros.js`.
|
||||
*/
|
||||
export const _macros: MacroMap = {};
|
||||
|
||||
// This function might one day accept an additional argument and do more things.
|
||||
export default function defineMacro(name: string, body: MacroDefinition) {
|
||||
_macros[name] = body;
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
// @flow
|
||||
import defineFunction, {ordargument} from "../defineFunction";
|
||||
import {defineMacro} from "../macros";
|
||||
import defineMacro from "../defineMacro";
|
||||
import buildCommon from "../buildCommon";
|
||||
import mathMLTree from "../mathMLTree";
|
||||
import {SymbolNode} from "../domTree";
|
||||
|
117
src/macros.js
117
src/macros.js
@@ -4,124 +4,17 @@
|
||||
* This can be used to define some commands in terms of others.
|
||||
*/
|
||||
|
||||
// Export global macros object from defineMacro
|
||||
import defineMacro, {_macros} from "./defineMacro";
|
||||
const macros = _macros;
|
||||
export default macros;
|
||||
|
||||
import fontMetricsData from "./fontMetricsData";
|
||||
import functions from "./functions";
|
||||
import symbols from "./symbols";
|
||||
import utils from "./utils";
|
||||
import {Token} from "./Token";
|
||||
import ParseError from "./ParseError";
|
||||
import type Namespace from "./Namespace";
|
||||
|
||||
import type {Mode} from "./types";
|
||||
|
||||
/**
|
||||
* Provides context to macros defined by functions. Implemented by
|
||||
* MacroExpander.
|
||||
*/
|
||||
export interface MacroContextInterface {
|
||||
mode: Mode;
|
||||
|
||||
/**
|
||||
* Object mapping macros to their expansions.
|
||||
*/
|
||||
macros: Namespace<MacroDefinition>;
|
||||
|
||||
/**
|
||||
* Returns the topmost token on the stack, without expanding it.
|
||||
* Similar in behavior to TeX's `\futurelet`.
|
||||
*/
|
||||
future(): Token;
|
||||
|
||||
/**
|
||||
* Remove and return the next unexpanded token.
|
||||
*/
|
||||
popToken(): Token;
|
||||
|
||||
/**
|
||||
* Consume all following space tokens, without expansion.
|
||||
*/
|
||||
consumeSpaces(): void;
|
||||
|
||||
/**
|
||||
* Expand the next token only once if possible.
|
||||
*/
|
||||
expandOnce(expandableOnly?: boolean): Token | Token[];
|
||||
|
||||
/**
|
||||
* Expand the next token only once (if possible), and return the resulting
|
||||
* top token on the stack (without removing anything from the stack).
|
||||
* Similar in behavior to TeX's `\expandafter\futurelet`.
|
||||
*/
|
||||
expandAfterFuture(): Token;
|
||||
|
||||
/**
|
||||
* Recursively expand first token, then return first non-expandable token.
|
||||
*/
|
||||
expandNextToken(): Token;
|
||||
|
||||
/**
|
||||
* Fully expand the given macro name and return the resulting list of
|
||||
* tokens, or return `undefined` if no such macro is defined.
|
||||
*/
|
||||
expandMacro(name: string): Token[] | void;
|
||||
|
||||
/**
|
||||
* Fully expand the given macro name and return the result as a string,
|
||||
* or return `undefined` if no such macro is defined.
|
||||
*/
|
||||
expandMacroAsText(name: string): string | void;
|
||||
|
||||
/**
|
||||
* Consume an argument from the token stream, and return the resulting array
|
||||
* of tokens and start/end token.
|
||||
*/
|
||||
consumeArg(delims?: ?string[]): MacroArg;
|
||||
|
||||
/**
|
||||
* Consume the specified number of arguments from the token stream,
|
||||
* and return the resulting array of arguments.
|
||||
*/
|
||||
consumeArgs(numArgs: number): Token[][];
|
||||
|
||||
/**
|
||||
* Determine whether a command is currently "defined" (has some
|
||||
* functionality), meaning that it's a macro (in the current group),
|
||||
* a function, a symbol, or one of the special commands listed in
|
||||
* `implicitCommands`.
|
||||
*/
|
||||
isDefined(name: string): boolean;
|
||||
|
||||
/**
|
||||
* Determine whether a command is expandable.
|
||||
*/
|
||||
isExpandable(name: string): boolean;
|
||||
}
|
||||
|
||||
export type MacroArg = {
|
||||
tokens: Token[],
|
||||
start: Token,
|
||||
end: Token
|
||||
};
|
||||
|
||||
/** Macro tokens (in reverse order). */
|
||||
export type MacroExpansion = {
|
||||
tokens: Token[],
|
||||
numArgs: number,
|
||||
delimiters?: string[][],
|
||||
unexpandable?: boolean, // used in \let
|
||||
};
|
||||
|
||||
export type MacroDefinition = string | MacroExpansion |
|
||||
(MacroContextInterface => (string | MacroExpansion));
|
||||
export type MacroMap = {[string]: MacroDefinition};
|
||||
|
||||
const builtinMacros: MacroMap = {};
|
||||
export default builtinMacros;
|
||||
|
||||
// This function might one day accept an additional argument and do more things.
|
||||
export function defineMacro(name: string, body: MacroDefinition) {
|
||||
builtinMacros[name] = body;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// macro tools
|
||||
|
Reference in New Issue
Block a user