openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

stex.js (6932B)


      1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
      2 // Distributed under an MIT license: http://codemirror.net/LICENSE
      3 
      4 /*
      5  * Author: Constantin Jucovschi (c.jucovschi@jacobs-university.de)
      6  * Licence: MIT
      7  */
      8 
      9 (function(mod) {
     10   if (typeof exports == "object" && typeof module == "object") // CommonJS
     11     mod(require("../../lib/codemirror"));
     12   else if (typeof define == "function" && define.amd) // AMD
     13     define(["../../lib/codemirror"], mod);
     14   else // Plain browser env
     15     mod(CodeMirror);
     16 })(function(CodeMirror) {
     17   "use strict";
     18 
     19   CodeMirror.defineMode("stex", function() {
     20     "use strict";
     21 
     22     function pushCommand(state, command) {
     23       state.cmdState.push(command);
     24     }
     25 
     26     function peekCommand(state) {
     27       if (state.cmdState.length > 0) {
     28         return state.cmdState[state.cmdState.length - 1];
     29       } else {
     30         return null;
     31       }
     32     }
     33 
     34     function popCommand(state) {
     35       var plug = state.cmdState.pop();
     36       if (plug) {
     37         plug.closeBracket();
     38       }
     39     }
     40 
     41     // returns the non-default plugin closest to the end of the list
     42     function getMostPowerful(state) {
     43       var context = state.cmdState;
     44       for (var i = context.length - 1; i >= 0; i--) {
     45         var plug = context[i];
     46         if (plug.name == "DEFAULT") {
     47           continue;
     48         }
     49         return plug;
     50       }
     51       return { styleIdentifier: function() { return null; } };
     52     }
     53 
     54     function addPluginPattern(pluginName, cmdStyle, styles) {
     55       return function () {
     56         this.name = pluginName;
     57         this.bracketNo = 0;
     58         this.style = cmdStyle;
     59         this.styles = styles;
     60         this.argument = null;   // \begin and \end have arguments that follow. These are stored in the plugin
     61 
     62         this.styleIdentifier = function() {
     63           return this.styles[this.bracketNo - 1] || null;
     64         };
     65         this.openBracket = function() {
     66           this.bracketNo++;
     67           return "bracket";
     68         };
     69         this.closeBracket = function() {};
     70       };
     71     }
     72 
     73     var plugins = {};
     74 
     75     plugins["importmodule"] = addPluginPattern("importmodule", "tag", ["string", "builtin"]);
     76     plugins["documentclass"] = addPluginPattern("documentclass", "tag", ["", "atom"]);
     77     plugins["usepackage"] = addPluginPattern("usepackage", "tag", ["atom"]);
     78     plugins["begin"] = addPluginPattern("begin", "tag", ["atom"]);
     79     plugins["end"] = addPluginPattern("end", "tag", ["atom"]);
     80 
     81     plugins["DEFAULT"] = function () {
     82       this.name = "DEFAULT";
     83       this.style = "tag";
     84 
     85       this.styleIdentifier = this.openBracket = this.closeBracket = function() {};
     86     };
     87 
     88     function setState(state, f) {
     89       state.f = f;
     90     }
     91 
     92     // called when in a normal (no environment) context
     93     function normal(source, state) {
     94       var plug;
     95       // Do we look like '\command' ?  If so, attempt to apply the plugin 'command'
     96       if (source.match(/^\\[a-zA-Z@]+/)) {
     97         var cmdName = source.current().slice(1);
     98         plug = plugins[cmdName] || plugins["DEFAULT"];
     99         plug = new plug();
    100         pushCommand(state, plug);
    101         setState(state, beginParams);
    102         return plug.style;
    103       }
    104 
    105       // escape characters
    106       if (source.match(/^\\[$&%#{}_]/)) {
    107         return "tag";
    108       }
    109 
    110       // white space control characters
    111       if (source.match(/^\\[,;!\/\\]/)) {
    112         return "tag";
    113       }
    114 
    115       // find if we're starting various math modes
    116       if (source.match("\\[")) {
    117         setState(state, function(source, state){ return inMathMode(source, state, "\\]"); });
    118         return "keyword";
    119       }
    120       if (source.match("$$")) {
    121         setState(state, function(source, state){ return inMathMode(source, state, "$$"); });
    122         return "keyword";
    123       }
    124       if (source.match("$")) {
    125         setState(state, function(source, state){ return inMathMode(source, state, "$"); });
    126         return "keyword";
    127       }
    128 
    129       var ch = source.next();
    130       if (ch == "%") {
    131         source.skipToEnd();
    132         return "comment";
    133       } else if (ch == '}' || ch == ']') {
    134         plug = peekCommand(state);
    135         if (plug) {
    136           plug.closeBracket(ch);
    137           setState(state, beginParams);
    138         } else {
    139           return "error";
    140         }
    141         return "bracket";
    142       } else if (ch == '{' || ch == '[') {
    143         plug = plugins["DEFAULT"];
    144         plug = new plug();
    145         pushCommand(state, plug);
    146         return "bracket";
    147       } else if (/\d/.test(ch)) {
    148         source.eatWhile(/[\w.%]/);
    149         return "atom";
    150       } else {
    151         source.eatWhile(/[\w\-_]/);
    152         plug = getMostPowerful(state);
    153         if (plug.name == 'begin') {
    154           plug.argument = source.current();
    155         }
    156         return plug.styleIdentifier();
    157       }
    158     }
    159 
    160     function inMathMode(source, state, endModeSeq) {
    161       if (source.eatSpace()) {
    162         return null;
    163       }
    164       if (source.match(endModeSeq)) {
    165         setState(state, normal);
    166         return "keyword";
    167       }
    168       if (source.match(/^\\[a-zA-Z@]+/)) {
    169         return "tag";
    170       }
    171       if (source.match(/^[a-zA-Z]+/)) {
    172         return "variable-2";
    173       }
    174       // escape characters
    175       if (source.match(/^\\[$&%#{}_]/)) {
    176         return "tag";
    177       }
    178       // white space control characters
    179       if (source.match(/^\\[,;!\/]/)) {
    180         return "tag";
    181       }
    182       // special math-mode characters
    183       if (source.match(/^[\^_&]/)) {
    184         return "tag";
    185       }
    186       // non-special characters
    187       if (source.match(/^[+\-<>|=,\/@!*:;'"`~#?]/)) {
    188         return null;
    189       }
    190       if (source.match(/^(\d+\.\d*|\d*\.\d+|\d+)/)) {
    191         return "number";
    192       }
    193       var ch = source.next();
    194       if (ch == "{" || ch == "}" || ch == "[" || ch == "]" || ch == "(" || ch == ")") {
    195         return "bracket";
    196       }
    197 
    198       if (ch == "%") {
    199         source.skipToEnd();
    200         return "comment";
    201       }
    202       return "error";
    203     }
    204 
    205     function beginParams(source, state) {
    206       var ch = source.peek(), lastPlug;
    207       if (ch == '{' || ch == '[') {
    208         lastPlug = peekCommand(state);
    209         lastPlug.openBracket(ch);
    210         source.eat(ch);
    211         setState(state, normal);
    212         return "bracket";
    213       }
    214       if (/[ \t\r]/.test(ch)) {
    215         source.eat(ch);
    216         return null;
    217       }
    218       setState(state, normal);
    219       popCommand(state);
    220 
    221       return normal(source, state);
    222     }
    223 
    224     return {
    225       startState: function() {
    226         return {
    227           cmdState: [],
    228           f: normal
    229         };
    230       },
    231       copyState: function(s) {
    232         return {
    233           cmdState: s.cmdState.slice(),
    234           f: s.f
    235         };
    236       },
    237       token: function(stream, state) {
    238         return state.f(stream, state);
    239       },
    240       blankLine: function(state) {
    241         state.f = normal;
    242         state.cmdState.length = 0;
    243       },
    244       lineComment: "%"
    245     };
    246   });
    247 
    248   CodeMirror.defineMIME("text/x-stex", "stex");
    249   CodeMirror.defineMIME("text/x-latex", "stex");
    250 
    251 });