123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264 |
- /* -*- Mode: Javascript; indent-tabs-mode:nil; js-indent-level: 2 -*- */
- /* vim: set ts=2 et sw=2 tw=80: */
- /*************************************************************
- *
- * MathJax/extensions/TeX/newcommand.js
- *
- * Implements the \newcommand, \newenvironment and \def
- * macros, and is loaded automatically when needed.
- *
- * ---------------------------------------------------------------------
- *
- * Copyright (c) 2009-2013 The MathJax Consortium
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- MathJax.Extension["TeX/newcommand"] = {
- version: "2.2"
- };
- MathJax.Hub.Register.StartupHook("TeX Jax Ready",function () {
-
- var TEX = MathJax.InputJax.TeX;
- var TEXDEF = TEX.Definitions;
-
- TEXDEF.Add({
- macros: {
- newcommand: 'NewCommand',
- renewcommand: 'NewCommand',
- newenvironment: 'NewEnvironment',
- renewenvironment: 'NewEnvironment',
- def: 'MacroDef',
- let: 'Let'
- }
- },null,true);
- TEX.Parse.Augment({
- /*
- * Implement \newcommand{\name}[n]{...}
- */
- NewCommand: function (name) {
- var cs = this.trimSpaces(this.GetArgument(name)),
- n = this.GetBrackets(name),
- opt = this.GetBrackets(name),
- def = this.GetArgument(name);
- if (cs.charAt(0) === "\\") {cs = cs.substr(1)}
- if (!cs.match(/^(.|[a-z]+)$/i)) {
- TEX.Error(["IllegalControlSequenceName",
- "Illegal control sequence name for %1",name]);
- }
- if (n) {
- n = this.trimSpaces(n);
- if (!n.match(/^[0-9]+$/)) {
- TEX.Error(["IllegalParamNumber",
- "Illegal number of parameters specified in %1",name]);
- }
- }
- this.setDef(cs,['Macro',def,n,opt]);
- },
-
- /*
- * Implement \newenvironment{name}[n][default]{begincmd}{endcmd}
- */
- NewEnvironment: function (name) {
- var env = this.trimSpaces(this.GetArgument(name)),
- n = this.GetBrackets(name),
- bdef = this.GetArgument(name),
- edef = this.GetArgument(name);
- if (n) {
- n = this.trimSpaces(n);
- if (!n.match(/^[0-9]+$/)) {
- TEX.Error(["IllegalParamNumber",
- "Illegal number of parameters specified in %1",name]);
- }
- }
- this.setEnv(env,['BeginEnv','EndEnv',bdef,edef,n]);
- },
-
- /*
- * Implement \def command
- */
- MacroDef: function (name) {
- var cs = this.GetCSname(name),
- params = this.GetTemplate(name,"\\"+cs),
- def = this.GetArgument(name);
- if (!(params instanceof Array)) {this.setDef(cs,['Macro',def,params])}
- else {this.setDef(cs,['MacroWithTemplate',def].concat(params))}
- },
-
- /*
- * Implements the \let command
- */
- Let: function (name) {
- var cs = this.GetCSname(name), macro;
- var c = this.GetNext(); if (c === "=") {this.i++; c = this.GetNext()}
- //
- // All \let commands create entries in the macros array, but we
- // have to look in the various mathchar and delimiter arrays if
- // the source isn't a macro already, and attach the data to a
- // macro with the proper routine to process it.
- //
- // A command of the form \let\cs=char produces a macro equivalent
- // to \def\cs{char}, which is as close as MathJax can get for this.
- // So \let\bgroup={ is possible, but doesn't work as it does in TeX.
- //
- if (c === "\\") {
- name = this.GetCSname(name);
- macro = this.csFindMacro(name);
- if (!macro) {
- if (TEXDEF.mathchar0mi[name]) {macro = ["csMathchar0mi",TEXDEF.mathchar0mi[name]]} else
- if (TEXDEF.mathchar0mo[name]) {macro = ["csMathchar0mo",TEXDEF.mathchar0mo[name]]} else
- if (TEXDEF.mathchar7[name]) {macro = ["csMathchar7",TEXDEF.mathchar7[name]]} else
- if (TEXDEF.delimiter["\\"+name] != null) {macro = ["csDelimiter",TEXDEF.delimiter["\\"+name]]}
- }
- } else {macro = ["Macro",c]; this.i++}
- this.setDef(cs,macro);
- },
-
- /*
- * Routines to set the macro and environment definitions
- * (overridden by begingroup to make localized versions)
- */
- setDef: function (name,value) {value.isUser = true; TEXDEF.macros[name] = value},
- setEnv: function (name,value) {value.isUser = true; TEXDEF.environment[name] = value},
-
- /*
- * Get a CS name or give an error
- */
- GetCSname: function (cmd) {
- var c = this.GetNext();
- if (c !== "\\") {
- TEX.Error(["DoubleBackSlash",
- "\\ must be followed by a control sequence"])
- }
- var cs = this.trimSpaces(this.GetArgument(cmd));
- return cs.substr(1);
- },
-
- /*
- * Get a \def parameter template
- */
- GetTemplate: function (cmd,cs) {
- var c, params = [], n = 0;
- c = this.GetNext(); var i = this.i;
- while (this.i < this.string.length) {
- c = this.GetNext();
- if (c === '#') {
- if (i !== this.i) {params[n] = this.string.substr(i,this.i-i)}
- c = this.string.charAt(++this.i);
- if (!c.match(/^[1-9]$/)) {
- TEX.Error(["CantUseHash2",
- "Illegal use of # in template for %1",cs]);
- }
- if (parseInt(c) != ++n) {
- TEX.Error(["SequentialParam",
- "Parameters for %1 must be numbered sequentially",cs]);
- }
- i = this.i+1;
- } else if (c === '{') {
- if (i !== this.i) {params[n] = this.string.substr(i,this.i-i)}
- if (params.length > 0) {return [n,params]} else {return n}
- }
- this.i++;
- }
- TEX.Error(["MissingReplacementString",
- "Missing replacement string for definition of %1",cmd]);
- },
-
- /*
- * Process a macro with a parameter template
- */
- MacroWithTemplate: function (name,text,n,params) {
- if (n) {
- var args = []; this.GetNext();
- if (params[0] && !this.MatchParam(params[0])) {
- TEX.Error(["MismatchUseDef",
- "Use of %1 doesn't match its definition",name]);
- }
- for (var i = 0; i < n; i++) {args.push(this.GetParameter(name,params[i+1]))}
- text = this.SubstituteArgs(args,text);
- }
- this.string = this.AddArgs(text,this.string.slice(this.i));
- this.i = 0;
- if (++this.macroCount > TEX.config.MAXMACROS) {
- TEX.Error(["MaxMacroSub1",
- "MathJax maximum macro substitution count exceeded; " +
- "is there a recursive macro call?"]);
- }
- },
-
- /*
- * Process a user-defined environment
- */
- BeginEnv: function (begin,bdef,edef,n) {
- if (n) {
- var args = [];
- for (var i = 0; i < n; i++) {args.push(this.GetArgument("\\begin{"+name+"}"))}
- bdef = this.SubstituteArgs(args,bdef);
- edef = this.SubstituteArgs(args,edef);
- }
- begin.edef = edef;
- this.string = this.AddArgs(bdef,this.string.slice(this.i)); this.i = 0;
- return begin;
- },
- EndEnv: function (begin,row) {
- this.string = this.AddArgs(begin.edef,this.string.slice(this.i)); this.i = 0
- return row;
- },
-
- /*
- * Find a single parameter delimited by a trailing template
- */
- GetParameter: function (name,param) {
- if (param == null) {return this.GetArgument(name)}
- var i = this.i, j = 0, hasBraces = 0;
- while (this.i < this.string.length) {
- if (this.string.charAt(this.i) === '{') {
- if (this.i === i) {hasBraces = 1}
- this.GetArgument(name); j = this.i - i;
- } else if (this.MatchParam(param)) {
- if (hasBraces) {i++; j -= 2}
- return this.string.substr(i,j);
- } else {
- this.i++; j++; hasBraces = 0;
- }
- }
- TEX.Error(["RunawayArgument","Runaway argument for %1?",name]);
- },
-
- /*
- * Check if a template is at the current location.
- * (The match must be exact, with no spacing differences. TeX is
- * a little more forgiving than this about spaces after macro names)
- */
- MatchParam: function (param) {
- if (this.string.substr(this.i,param.length) !== param) {return 0}
- this.i += param.length;
- return 1;
- }
-
- });
-
- TEX.Environment = function (name) {
- TEXDEF.environment[name] = ['BeginEnv','EndEnv'].concat([].slice.call(arguments,1));
- TEXDEF.environment[name].isUser = true;
- }
- MathJax.Hub.Startup.signal.Post("TeX newcommand Ready");
- });
- MathJax.Ajax.loadComplete("[MathJax]/extensions/TeX/newcommand.js");
|