mirror of
				https://github.com/kovidgoyal/calibre.git
				synced 2025-10-31 02:27:01 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			270 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			270 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| /* -*- 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-2015 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.6.0"
 | |
| };
 | |
| 
 | |
| 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][default]{...}
 | |
|      */
 | |
|     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),
 | |
|           opt  = 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',[null,'EndEnv'],bdef,edef,n,opt]);
 | |
|     },
 | |
|     
 | |
|     /*
 | |
|      *  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(["MissingCS",
 | |
|                    "%1 must be followed by a control sequence", cmd])
 | |
|       }
 | |
|       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,def) {
 | |
|       if (n) {
 | |
|         var args = [];
 | |
|         if (def != null) {
 | |
|           var optional = this.GetBrackets("\\begin{"+name+"}");
 | |
|           args.push(optional == null ? def : optional);
 | |
|         }
 | |
|         for (var i = args.length; i < n; i++) {args.push(this.GetArgument("\\begin{"+name+"}"))}
 | |
|         bdef = this.SubstituteArgs(args,bdef);
 | |
|         edef = this.SubstituteArgs([],edef); // no args, but get errors for #n in edef
 | |
|       }
 | |
|       this.string = this.AddArgs(bdef,this.string.slice(this.i)); this.i = 0;
 | |
|       return begin;
 | |
|     },
 | |
|     EndEnv: function (begin,bdef,edef,n) {
 | |
|       var end = "\\end{\\end\\"+begin.name+"}"; // special version of \end for after edef
 | |
|       this.string = this.AddArgs(edef,end+this.string.slice(this.i)); this.i = 0;
 | |
|       return null;
 | |
|     },
 | |
|     
 | |
|     /*
 | |
|      *  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");
 |