Subversion-Projekte lars-tiefland.cienc

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
5 lars 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
});