AutoloadConfiguration.ts 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /*************************************************************
  2. *
  3. * Copyright (c) 2019-2022 The MathJax Consortium
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. /**
  18. * @fileoverview Configuration file for the autoload package.
  19. *
  20. * @author dpvc@mathjax.org (Davide P. Cervone)
  21. */
  22. import {Configuration, ParserConfiguration} from '../Configuration.js';
  23. import TexParser from '../TexParser.js';
  24. import {CommandMap} from '../SymbolMap.js';
  25. import {Macro} from '../Symbol.js';
  26. import {TeX} from '../../tex.js';
  27. import {RequireLoad, RequireConfiguration} from '../require/RequireConfiguration.js';
  28. import {Package} from '../../../components/package.js';
  29. import {expandable, defaultOptions} from '../../../util/Options.js';
  30. /**
  31. * Autoload an extension when the first macro for it is encountered
  32. * (if the extension has already been loaded, remove the autoload
  33. * macros and environments so they won't try to load it again, and
  34. * back up to read the macro again, call the RequireLoad command to
  35. * either load the extension, or initialize it.)
  36. *
  37. * @param {TexParser} parser The TeX input parser
  38. * @param {string} name The control sequence that is running
  39. * @param {string} extension The extension to load
  40. * @param {boolean} isMacro True if this is a macro, false if an environment
  41. */
  42. function Autoload(parser: TexParser, name: string, extension: string, isMacro: boolean) {
  43. if (Package.packages.has(parser.options.require.prefix + extension)) {
  44. const def = parser.options.autoload[extension];
  45. const [macros, envs] = (def.length === 2 && Array.isArray(def[0]) ? def : [def, []]);
  46. for (const macro of macros) {
  47. AutoloadMacros.remove(macro);
  48. }
  49. for (const env of envs) {
  50. AutoloadEnvironments.remove(env);
  51. }
  52. //
  53. // Put back the macro or \begin and read it again
  54. //
  55. parser.string = (isMacro ? name + ' ' : '\\begin{' + name.slice(1) + '}' ) + parser.string.slice(parser.i);
  56. parser.i = 0;
  57. }
  58. RequireLoad(parser, extension);
  59. }
  60. /**
  61. * Check if the require extension has been initialized
  62. * (If autoload has been included in the TeX packages, but require isn't, then we need
  63. * to set up the options here and configure the require package in configAutoload below.
  64. * the priorities of the initialization and configuration are set so that autoload
  65. * will run after require when both are used.)
  66. */
  67. function initAutoload(config: ParserConfiguration) {
  68. if (!config.options.require) {
  69. defaultOptions(config.options, RequireConfiguration.options);
  70. }
  71. }
  72. /**
  73. * Create the macros and environments for the extensions that need to be loaded.
  74. * Only ones that aren't already defined are made to autoload
  75. * (except for \color, which is overridden if present)
  76. */
  77. function configAutoload(config: ParserConfiguration, jax: TeX<any, any, any>) {
  78. const parser = jax.parseOptions;
  79. const macros = parser.handlers.get('macro');
  80. const environments = parser.handlers.get('environment');
  81. const autoload = parser.options.autoload;
  82. parser.packageData.set('autoload', {Autoload}); // used by textmacros to tell if a macro is autoloading
  83. //
  84. // Loop through the autoload definitions
  85. //
  86. for (const extension of Object.keys(autoload)) {
  87. const def = autoload[extension];
  88. const [macs, envs] = (def.length === 2 && Array.isArray(def[0]) ? def : [def, []]);
  89. //
  90. // Create the macros
  91. //
  92. for (const name of macs) {
  93. if (!macros.lookup(name) || name === 'color') {
  94. AutoloadMacros.add(name, new Macro(name, Autoload, [extension, true]));
  95. }
  96. }
  97. //
  98. // Create the environments
  99. //
  100. for (const name of envs) {
  101. if (!environments.lookup(name)) {
  102. AutoloadEnvironments.add(name, new Macro(name, Autoload, [extension, false]));
  103. }
  104. }
  105. }
  106. //
  107. // Check if the require extension needs to be configured
  108. //
  109. if (!parser.packageData.get('require')) {
  110. RequireConfiguration.config(config, jax);
  111. }
  112. }
  113. /**
  114. * The command and environment maps for the macros that autoload extensions
  115. */
  116. const AutoloadMacros = new CommandMap('autoload-macros', {}, {});
  117. const AutoloadEnvironments = new CommandMap('autoload-environments', {}, {});
  118. /**
  119. * The configuration object for configmacros
  120. */
  121. export const AutoloadConfiguration = Configuration.create(
  122. 'autoload', {
  123. handler: {
  124. macro: ['autoload-macros'],
  125. environment: ['autoload-environments']
  126. },
  127. options: {
  128. //
  129. // These are the extension names and the macros and environments they contain.
  130. // The format is [macros...] or [[macros...], [environments...]]
  131. // You can prevent one from being autoloaded by setting
  132. // it to [] in the options when the TeX input jax is created.
  133. // You can include the prefix if it is not the default one from require
  134. //
  135. autoload: expandable({
  136. action: ['toggle', 'mathtip', 'texttip'],
  137. amscd: [[], ['CD']],
  138. bbox: ['bbox'],
  139. boldsymbol: ['boldsymbol'],
  140. braket: ['bra', 'ket', 'braket', 'set', 'Bra', 'Ket', 'Braket', 'Set', 'ketbra', 'Ketbra'],
  141. bussproofs: [[], ['prooftree']],
  142. cancel: ['cancel', 'bcancel', 'xcancel', 'cancelto'],
  143. color: ['color', 'definecolor', 'textcolor', 'colorbox', 'fcolorbox'],
  144. enclose: ['enclose'],
  145. extpfeil: ['xtwoheadrightarrow', 'xtwoheadleftarrow', 'xmapsto', 'xlongequal', 'xtofrom', 'Newextarrow'],
  146. html: ['href', 'class', 'style', 'cssId'],
  147. mhchem: ['ce', 'pu'],
  148. newcommand: ['newcommand', 'renewcommand', 'newenvironment', 'renewenvironment', 'def', 'let'],
  149. unicode: ['unicode'],
  150. verb: ['verb']
  151. })
  152. },
  153. config: configAutoload,
  154. init: initAutoload,
  155. priority: 10
  156. }
  157. );