all repos — NoPaste @ edb00b0ab136a96023b51a3e1c59d21a807d66a2

Resurrected - The PussTheCat.org fork of NoPaste

scripts/CodeMirror/mode/stex/stex.js (view raw)

  1// CodeMirror, copyright (c) by Marijn Haverbeke and others
  2// Distributed under an MIT license: https://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(_config, parserConfig) {
 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["label"    ] = addPluginPattern("label"    , "tag", ["atom"]);
 82    plugins["ref"      ] = addPluginPattern("ref"      , "tag", ["atom"]);
 83    plugins["eqref"    ] = addPluginPattern("eqref"    , "tag", ["atom"]);
 84    plugins["cite"     ] = addPluginPattern("cite"     , "tag", ["atom"]);
 85    plugins["bibitem"  ] = addPluginPattern("bibitem"  , "tag", ["atom"]);
 86    plugins["Bibitem"  ] = addPluginPattern("Bibitem"  , "tag", ["atom"]);
 87    plugins["RBibitem" ] = addPluginPattern("RBibitem" , "tag", ["atom"]);
 88
 89    plugins["DEFAULT"] = function () {
 90      this.name = "DEFAULT";
 91      this.style = "tag";
 92
 93      this.styleIdentifier = this.openBracket = this.closeBracket = function() {};
 94    };
 95
 96    function setState(state, f) {
 97      state.f = f;
 98    }
 99
100    // called when in a normal (no environment) context
101    function normal(source, state) {
102      var plug;
103      // Do we look like '\command' ?  If so, attempt to apply the plugin 'command'
104      if (source.match(/^\\[a-zA-Z@]+/)) {
105        var cmdName = source.current().slice(1);
106        plug = plugins.hasOwnProperty(cmdName) ? plugins[cmdName] : plugins["DEFAULT"];
107        plug = new plug();
108        pushCommand(state, plug);
109        setState(state, beginParams);
110        return plug.style;
111      }
112
113      // escape characters
114      if (source.match(/^\\[$&%#{}_]/)) {
115        return "tag";
116      }
117
118      // white space control characters
119      if (source.match(/^\\[,;!\/\\]/)) {
120        return "tag";
121      }
122
123      // find if we're starting various math modes
124      if (source.match("\\[")) {
125        setState(state, function(source, state){ return inMathMode(source, state, "\\]"); });
126        return "keyword";
127      }
128      if (source.match("\\(")) {
129        setState(state, function(source, state){ return inMathMode(source, state, "\\)"); });
130        return "keyword";
131      }
132      if (source.match("$$")) {
133        setState(state, function(source, state){ return inMathMode(source, state, "$$"); });
134        return "keyword";
135      }
136      if (source.match("$")) {
137        setState(state, function(source, state){ return inMathMode(source, state, "$"); });
138        return "keyword";
139      }
140
141      var ch = source.next();
142      if (ch == "%") {
143        source.skipToEnd();
144        return "comment";
145      } else if (ch == '}' || ch == ']') {
146        plug = peekCommand(state);
147        if (plug) {
148          plug.closeBracket(ch);
149          setState(state, beginParams);
150        } else {
151          return "error";
152        }
153        return "bracket";
154      } else if (ch == '{' || ch == '[') {
155        plug = plugins["DEFAULT"];
156        plug = new plug();
157        pushCommand(state, plug);
158        return "bracket";
159      } else if (/\d/.test(ch)) {
160        source.eatWhile(/[\w.%]/);
161        return "atom";
162      } else {
163        source.eatWhile(/[\w\-_]/);
164        plug = getMostPowerful(state);
165        if (plug.name == 'begin') {
166          plug.argument = source.current();
167        }
168        return plug.styleIdentifier();
169      }
170    }
171
172    function inMathMode(source, state, endModeSeq) {
173      if (source.eatSpace()) {
174        return null;
175      }
176      if (endModeSeq && source.match(endModeSeq)) {
177        setState(state, normal);
178        return "keyword";
179      }
180      if (source.match(/^\\[a-zA-Z@]+/)) {
181        return "tag";
182      }
183      if (source.match(/^[a-zA-Z]+/)) {
184        return "variable-2";
185      }
186      // escape characters
187      if (source.match(/^\\[$&%#{}_]/)) {
188        return "tag";
189      }
190      // white space control characters
191      if (source.match(/^\\[,;!\/]/)) {
192        return "tag";
193      }
194      // special math-mode characters
195      if (source.match(/^[\^_&]/)) {
196        return "tag";
197      }
198      // non-special characters
199      if (source.match(/^[+\-<>|=,\/@!*:;'"`~#?]/)) {
200        return null;
201      }
202      if (source.match(/^(\d+\.\d*|\d*\.\d+|\d+)/)) {
203        return "number";
204      }
205      var ch = source.next();
206      if (ch == "{" || ch == "}" || ch == "[" || ch == "]" || ch == "(" || ch == ")") {
207        return "bracket";
208      }
209
210      if (ch == "%") {
211        source.skipToEnd();
212        return "comment";
213      }
214      return "error";
215    }
216
217    function beginParams(source, state) {
218      var ch = source.peek(), lastPlug;
219      if (ch == '{' || ch == '[') {
220        lastPlug = peekCommand(state);
221        lastPlug.openBracket(ch);
222        source.eat(ch);
223        setState(state, normal);
224        return "bracket";
225      }
226      if (/[ \t\r]/.test(ch)) {
227        source.eat(ch);
228        return null;
229      }
230      setState(state, normal);
231      popCommand(state);
232
233      return normal(source, state);
234    }
235
236    return {
237      startState: function() {
238        var f = parserConfig.inMathMode ? function(source, state){ return inMathMode(source, state); } : normal;
239        return {
240          cmdState: [],
241          f: f
242        };
243      },
244      copyState: function(s) {
245        return {
246          cmdState: s.cmdState.slice(),
247          f: s.f
248        };
249      },
250      token: function(stream, state) {
251        return state.f(stream, state);
252      },
253      blankLine: function(state) {
254        state.f = normal;
255        state.cmdState.length = 0;
256      },
257      lineComment: "%"
258    };
259  });
260
261  CodeMirror.defineMIME("text/x-stex", "stex");
262  CodeMirror.defineMIME("text/x-latex", "stex");
263
264});