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