diff --git a/mathjax3-ts/input/tex.ts b/mathjax3-ts/input/tex.ts index 8581227f5..12ce37ea4 100644 --- a/mathjax3-ts/input/tex.ts +++ b/mathjax3-ts/input/tex.ts @@ -110,7 +110,7 @@ export class TeX extends AbstractInputJax { configuration.append(conf); } } - configuration.append(Configuration.extension()); + configuration.init(configuration); return configuration; } diff --git a/mathjax3-ts/input/tex/Configuration.ts b/mathjax3-ts/input/tex/Configuration.ts index f0c7157c9..f1cd8c0a1 100644 --- a/mathjax3-ts/input/tex/Configuration.ts +++ b/mathjax3-ts/input/tex/Configuration.ts @@ -43,6 +43,13 @@ export type ProcessorList = (Function | [Function, number])[] export class Configuration { + + /** + * Priority list of init methods. + * @type {FunctionList} + */ + protected initMethod: FunctionList = new FunctionList(); + /** * Creates a configuration for a package. * @param {string} name The package name. @@ -58,6 +65,8 @@ export class Configuration { * string wrt. to given parse options. Can contain a priority. * * _postprocessors_ list of functions for postprocessing the MmlNode * wrt. to given parse options. Can contain a priority. + * * _init_ init method. + * * _priority_ priority of the init method. * @return {Configuration} The newly generated configuration. */ public static create(name: string, @@ -68,7 +77,9 @@ export class Configuration { options?: OptionList, nodes?: {[key: string]: any}, preprocessors?: ProcessorList, - postprocessors?: ProcessorList + postprocessors?: ProcessorList, + init?: Function, + priority?: number } = {}) { return new Configuration(name, config.handler || {}, @@ -78,13 +89,14 @@ export class Configuration { config.options || {}, config.nodes || {}, config.preprocessors || [], - config.postprocessors || [] + config.postprocessors || [], + [config.init, config.priority] ); } /** - * An empty configuration. + * @return {Configuration} An empty configuration. */ public static empty(): Configuration { return Configuration.create('empty'); @@ -92,7 +104,7 @@ export class Configuration { /** - * Initialises extension maps. + * @return {Configuration} Initialises and returns the extension maps. */ public static extension(): Configuration { new sm.MacroMap(ExtensionMaps.NEW_MACRO, {}, {}); @@ -113,6 +125,14 @@ export class Configuration { }; + /** + * Init method for the configuration. + */ + public init(configuration: Configuration) { + this.initMethod.execute(configuration); + } + + /** * Appends configurations to this configuration. Note that fallbacks are * overwritten, while order of configurations is preserved. @@ -138,6 +158,9 @@ export class Configuration { for (let post of config.postprocessors) { this.postprocessors.push(post); }; + for (let init of config.initMethod.toArray()) { + this.initMethod.add(init.item, init.priority); + }; } @@ -152,8 +175,12 @@ export class Configuration { readonly options: OptionList = {}, readonly nodes: {[key: string]: any} = {}, readonly preprocessors: ProcessorList = [], - readonly postprocessors: ProcessorList = [] + readonly postprocessors: ProcessorList = [], + [init, priority]: [Function, number] ) { + if (init) { + this.initMethod.add(init, priority || 0); + } this.handler = Object.assign( {character: [], delimiter: [], macro: [], environment: []}, handler); ConfigurationHandler.set(name, this); @@ -194,5 +221,3 @@ export namespace ConfigurationHandler { }; } - - diff --git a/mathjax3-ts/input/tex/FindTeX.ts b/mathjax3-ts/input/tex/FindTeX.ts index 87b51d3d0..ad40c3fb7 100644 --- a/mathjax3-ts/input/tex/FindTeX.ts +++ b/mathjax3-ts/input/tex/FindTeX.ts @@ -26,7 +26,7 @@ import {OptionList} from '../../util/Options.js'; import {sortLength, quotePattern} from '../../util/string.js'; import {MathItem, ProtoItem, protoItem, Location} from '../../core/MathItem.js'; -/* +/** * Shorthand types for data about end delimiters and delimiter pairs */ export type EndItem = [string, boolean, RegExp]; @@ -46,6 +46,9 @@ export type Delims = [string, string]; */ export class FindTeX extends AbstractFindMath { + /** + * @type {OptionList} + */ public static OPTIONS: OptionList = { inlineMath: [ // The start/end delimiter pairs for in-line math // ['$', '$'], // (comment out any you don't want, or add your own, but @@ -64,32 +67,32 @@ export class FindTeX extends AbstractFindMath { processRefs: true, // set to true to process \ref{...} outside of math mode }; - /* + /** * The regular expression for any starting delimiter */ protected start: RegExp; - /* + /** * The end-delimiter data keyed to the opening delimiter string */ protected end: {[name: string]: EndItem}; - /* + /** * False if the configuration has no delimiters (so search can be skipped), true otherwise */ protected hasPatterns: boolean; - /* + /** * The index of the \begin...\end pattern in the regex match array */ protected env: number; - /* + /** * The index of the \ref and escaped character patters in the regex match array */ protected sub: number; - /* + /** * @override */ constructor(options: OptionList) { @@ -97,7 +100,7 @@ export class FindTeX extends AbstractFindMath { this.getPatterns(); } - /* + /** * Create the patterns needed for searching the strings for TeX * based on the configuration options */ @@ -131,7 +134,7 @@ export class FindTeX extends AbstractFindMath { this.hasPatterns = (parts.length > 0); } - /* + /** * Add the needed patterns for a pair of delimiters * * @param {string[]} starts Array of starting delimiter strings @@ -144,7 +147,7 @@ export class FindTeX extends AbstractFindMath { this.end[open] = [close, display, this.endPattern(close)]; } - /* + /** * Create the pattern for a close delimiter * * @param {string} end The end delimiter text @@ -154,7 +157,7 @@ export class FindTeX extends AbstractFindMath { return new RegExp(quotePattern(end) + '|\\\\(?:[a-zA-Z]|.)|[{}]', 'g'); } - /* + /** * Search for the end delimiter given the start delimiter, * skipping braced groups, and control sequences that aren't * the close delimiter. @@ -182,7 +185,7 @@ export class FindTeX extends AbstractFindMath { return null; } - /* + /** * Search a string for math delimited by one of the delimiter pairs, * or by \begin{env}...\end{env}, or \eqref{...}, \ref{...}, \\, or \$. * @@ -219,7 +222,7 @@ export class FindTeX extends AbstractFindMath { } } - /* + /** * Search for math in an array of strings and return an array of matches. * * @override diff --git a/mathjax3-ts/input/tex/StackItem.ts b/mathjax3-ts/input/tex/StackItem.ts index 7f73bd2ca..e81e21674 100644 --- a/mathjax3-ts/input/tex/StackItem.ts +++ b/mathjax3-ts/input/tex/StackItem.ts @@ -280,7 +280,7 @@ export interface StackItem extends NodeStack { * @return {StackItem} Returns the stack item object for pipelining. */ setProperties(def: PropList): StackItem; - + /** * Convenience method for returning the string property "name". * @return {string} The value for the name property. @@ -292,10 +292,10 @@ export interface StackItem extends NodeStack { * automaton. That is the tex parser works on a stack, and each item on the * stack can have a data stack of its own. Data on the stack is either a stack * item or a node. - * + * * The checkItem method effectively implements the recursive checking of * input data from the parser against data recursively given on the stack. - * + * * I.e., new input is parsed resulting in a new item. When pushed on the stack * it is checked against the top most item on the stack. This either leads to * the item being pushed onto the stack or combined with the top most @@ -306,7 +306,7 @@ export interface StackItem extends NodeStack { * the stack. Nodes on the stack are collapsed into content of the 'foo' * environment, until a beginItem for 'foo' is found. If a beginItem is not * for 'foo' or does not exist an error is thrown. - * + * * @param {StackItem} item The pushed item. * @return {CheckType} True/false or an item or node. */ diff --git a/mathjax3-ts/input/tex/ams/AmsConfiguration.ts b/mathjax3-ts/input/tex/ams/AmsConfiguration.ts index 85ea98144..3ad2e8847 100644 --- a/mathjax3-ts/input/tex/ams/AmsConfiguration.ts +++ b/mathjax3-ts/input/tex/ams/AmsConfiguration.ts @@ -23,6 +23,7 @@ */ import {Configuration} from '../Configuration.js'; +import {CommandMap} from '../SymbolMap.js'; import TexParser from '../TexParser.js'; import {MultlineItem} from './AmsItems.js'; import {AbstractTags} from '../Tags.js'; @@ -37,6 +38,14 @@ import './AmsMappings.js'; export class AmsTags extends AbstractTags { } +/** + * Init method for AMS package. + * @param {Configuration} config The current configuration. + */ +let init = function(config: Configuration) { + config.append(Configuration.extension()); +}; + export const AmsConfiguration = Configuration.create( 'ams', {handler: { @@ -47,7 +56,9 @@ export const AmsConfiguration = Configuration.create( environment: ['AMSmath-environment'] }, items: {[MultlineItem.prototype.kind]: MultlineItem}, - tags: {'AMS': AmsTags}} + tags: {'AMS': AmsTags}, + init: init + } ); diff --git a/mathjax3-ts/input/tex/ams/AmsMethods.ts b/mathjax3-ts/input/tex/ams/AmsMethods.ts index df4eac65e..bf2849ebf 100644 --- a/mathjax3-ts/input/tex/ams/AmsMethods.ts +++ b/mathjax3-ts/input/tex/ams/AmsMethods.ts @@ -33,7 +33,7 @@ import TexError from '../TexError.js'; import {Label} from '../Tags.js'; import {Macro} from '../Symbol.js'; import {CommandMap} from '../SymbolMap.js'; -import {MapHandler} from '../MapHandler.js'; +import {MapHandler, ExtensionMaps} from '../MapHandler.js'; import {ArrayItem} from '../base/BaseItems.js'; import BaseMethods from '../base/BaseMethods.js'; import {MmlNode, TEXCLASS} from '../../../core/MmlTree/MmlNode.js'; @@ -143,9 +143,7 @@ AmsMethods.HandleDeclareOp = function (parser: TexParser, name: string) { } let op = parser.GetArgument(name); op = op.replace(/\*/g, '\\text{*}').replace(/-/g, '\\text{-}'); - // TODO: Use a better dedicated handler. - // What about already defined commands? - (MapHandler.getMap('new-Command') as CommandMap). + (parser.configuration.handlers.retrieve(ExtensionMaps.NEW_COMMAND) as CommandMap). add(cs, new Macro(cs, AmsMethods.Macro, ['\\mathop{\\rm ' + op + '}' + limits])); }; diff --git a/mathjax3-ts/input/tex/base/BaseMappings.ts b/mathjax3-ts/input/tex/base/BaseMappings.ts index a18290c3f..1f0ee9176 100644 --- a/mathjax3-ts/input/tex/base/BaseMappings.ts +++ b/mathjax3-ts/input/tex/base/BaseMappings.ts @@ -548,7 +548,6 @@ new sm.CommandMap('macros', { vcenter: ['TeXAtom', TEXCLASS.VCENTER], - // mathchoice: ['Extension', 'mathchoice'], buildrel: 'BuildRel', hbox: ['HBox', 0], diff --git a/mathjax3-ts/input/tex/newcommand/NewcommandConfiguration.ts b/mathjax3-ts/input/tex/newcommand/NewcommandConfiguration.ts index 2907a1ebc..45aedccd2 100644 --- a/mathjax3-ts/input/tex/newcommand/NewcommandConfiguration.ts +++ b/mathjax3-ts/input/tex/newcommand/NewcommandConfiguration.ts @@ -27,6 +27,15 @@ import {BeginEnvItem} from './NewcommandItems.js'; import './NewcommandMappings.js'; +/** + * Init method for Newcommand package. + * @param {Configuration} config The current configuration. + */ +let init = function(config: Configuration) { + config.append(Configuration.extension()); +}; + + export const NewcommandConfiguration = Configuration.create( 'newcommand', {handler: { @@ -35,7 +44,8 @@ export const NewcommandConfiguration = Configuration.create( items: { [BeginEnvItem.prototype.kind]: BeginEnvItem, }, - options: {maxMacros: 1000} + options: {maxMacros: 1000}, + init: init } ); diff --git a/tests/parser-ams-tests.js b/tests/parser-ams-tests.js index 6763865fb..a57cb70b7 100644 --- a/tests/parser-ams-tests.js +++ b/tests/parser-ams-tests.js @@ -3073,7 +3073,7 @@ parserTest.runTest( "text": "∫"}], "isEmbellished": true}], "isInferred": true}]} -); +); parserTest.runTest( @@ -3324,7 +3324,7 @@ parserTest.runTest( "texClass": 0, "attributes": {}, "inherited": {"displaystyle": true, - "scriptlevel": 0}, + "scriptlevel": 0}, "properties": {"texprimestyle": true, "movablelimits": false}, "childNodes": [ @@ -3457,4 +3457,66 @@ parserTest.runTest( "isInferred": true}]} ); +parserTest.runTest( + 'DeclareMathOp', '\\DeclareMathOperator{\\R}{R}a\\R b', + {"kind": "math", + "texClass": 0, + "attributes": {"display": "block"}, + "inherited": {"displaystyle": true, + "scriptlevel": 0}, + "properties": {}, + "childNodes": [ + {"kind": "mrow", + "texClass": 0, + "attributes": {}, + "inherited": {"displaystyle": true, + "scriptlevel": 0}, + "properties": {}, + "childNodes": [ + {"kind": "mi", + "texClass": 0, + "attributes": {}, + "inherited": {"displaystyle": true, + "scriptlevel": 0, + "mathvariant": "italic"}, + "properties": {}, + "childNodes": [ + {"kind": "text", + "text": "a"}]}, + {"kind": "mi", + "texClass": 1, + "attributes": {"mathvariant": "normal"}, + "inherited": {"displaystyle": true, + "scriptlevel": 0, + "mathvariant": "italic"}, + "properties": {"movablelimits": false, + "movesupsub": false, + "fnOP": true}, + "childNodes": [ + {"kind": "text", + "text": "R"}]}, + {"kind": "mo", + "texClass": -1, + "attributes": {}, + "inherited": {"displaystyle": true, + "scriptlevel": 0, + "form": "infix"}, + "properties": {}, + "childNodes": [ + {"kind": "text", + "text": "⁡"}], + "isEmbellished": true}, + {"kind": "mi", + "texClass": 0, + "attributes": {}, + "inherited": {"displaystyle": true, + "scriptlevel": 0, + "mathvariant": "italic"}, + "properties": {}, + "childNodes": [ + {"kind": "text", + "text": "b"}]}], + "isInferred": true}]} +); + parserTest.printTime();