aboutsummaryrefslogtreecommitdiff
path: root/imports/codemirror/mode/python/python.js
diff options
context:
space:
mode:
Diffstat (limited to 'imports/codemirror/mode/python/python.js')
-rwxr-xr-ximports/codemirror/mode/python/python.js333
1 files changed, 333 insertions, 0 deletions
diff --git a/imports/codemirror/mode/python/python.js b/imports/codemirror/mode/python/python.js
new file mode 100755
index 00000000..382052ba
--- /dev/null
+++ b/imports/codemirror/mode/python/python.js
@@ -0,0 +1,333 @@
1CodeMirror.defineMode("python", function(conf, parserConf) {
2 var ERRORCLASS = 'error';
3
4 function wordRegexp(words) {
5 return new RegExp("^((" + words.join(")|(") + "))\\b");
6 }
7
8 var singleOperators = new RegExp("^[\\+\\-\\*/%&|\\^~<>!]");
9 var singleDelimiters = new RegExp('^[\\(\\)\\[\\]\\{\\}@,:`=;\\.]');
10 var doubleOperators = new RegExp("^((==)|(!=)|(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))");
11 var doubleDelimiters = new RegExp("^((\\+=)|(\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))");
12 var tripleDelimiters = new RegExp("^((//=)|(>>=)|(<<=)|(\\*\\*=))");
13 var identifiers = new RegExp("^[_A-Za-z][_A-Za-z0-9]*");
14
15 var wordOperators = wordRegexp(['and', 'or', 'not', 'is', 'in']);
16 var commonkeywords = ['as', 'assert', 'break', 'class', 'continue',
17 'def', 'del', 'elif', 'else', 'except', 'finally',
18 'for', 'from', 'global', 'if', 'import',
19 'lambda', 'pass', 'raise', 'return',
20 'try', 'while', 'with', 'yield'];
21 var commontypes = ['bool', 'classmethod', 'complex', 'dict', 'enumerate',
22 'float', 'frozenset', 'int', 'list', 'object',
23 'property', 'reversed', 'set', 'slice', 'staticmethod',
24 'str', 'super', 'tuple', 'type'];
25 var py2 = {'types': ['basestring', 'buffer', 'file', 'long', 'unicode',
26 'xrange'],
27 'keywords': ['exec', 'print']};
28 var py3 = {'types': ['bytearray', 'bytes', 'filter', 'map', 'memoryview',
29 'open', 'range', 'zip'],
30 'keywords': ['nonlocal']};
31
32 if (!!parserConf.version && parseInt(parserConf.version, 10) === 3) {
33 commonkeywords = commonkeywords.concat(py3.keywords);
34 commontypes = commontypes.concat(py3.types);
35 var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i");
36 } else {
37 commonkeywords = commonkeywords.concat(py2.keywords);
38 commontypes = commontypes.concat(py2.types);
39 var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))", "i");
40 }
41 var keywords = wordRegexp(commonkeywords);
42 var types = wordRegexp(commontypes);
43
44 var indentInfo = null;
45
46 // tokenizers
47 function tokenBase(stream, state) {
48 // Handle scope changes
49 if (stream.sol()) {
50 var scopeOffset = state.scopes[0].offset;
51 if (stream.eatSpace()) {
52 var lineOffset = stream.indentation();
53 if (lineOffset > scopeOffset) {
54 indentInfo = 'indent';
55 } else if (lineOffset < scopeOffset) {
56 indentInfo = 'dedent';
57 }
58 return null;
59 } else {
60 if (scopeOffset > 0) {
61 dedent(stream, state);
62 }
63 }
64 }
65 if (stream.eatSpace()) {
66 return null;
67 }
68
69 var ch = stream.peek();
70
71 // Handle Comments
72 if (ch === '#') {
73 stream.skipToEnd();
74 return 'comment';
75 }
76
77 // Handle Number Literals
78 if (stream.match(/^[0-9\.]/, false)) {
79 var floatLiteral = false;
80 // Floats
81 if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; }
82 if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; }
83 if (stream.match(/^\.\d+/)) { floatLiteral = true; }
84 if (floatLiteral) {
85 // Float literals may be "imaginary"
86 stream.eat(/J/i);
87 return 'number';
88 }
89 // Integers
90 var intLiteral = false;
91 // Hex
92 if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; }
93 // Binary
94 if (stream.match(/^0b[01]+/i)) { intLiteral = true; }
95 // Octal
96 if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; }
97 // Decimal
98 if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) {
99 // Decimal literals may be "imaginary"
100 stream.eat(/J/i);
101 // TODO - Can you have imaginary longs?
102 intLiteral = true;
103 }
104 // Zero by itself with no other piece of number.
105 if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; }
106 if (intLiteral) {
107 // Integer literals may be "long"
108 stream.eat(/L/i);
109 return 'number';
110 }
111 }
112
113 // Handle Strings
114 if (stream.match(stringPrefixes)) {
115 state.tokenize = tokenStringFactory(stream.current());
116 return state.tokenize(stream, state);
117 }
118
119 // Handle operators and Delimiters
120 if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) {
121 return null;
122 }
123 if (stream.match(doubleOperators)
124 || stream.match(singleOperators)
125 || stream.match(wordOperators)) {
126 return 'operator';
127 }
128 if (stream.match(singleDelimiters)) {
129 return null;
130 }
131
132 if (stream.match(types)) {
133 return 'builtin';
134 }
135
136 if (stream.match(keywords)) {
137 return 'keyword';
138 }
139
140 if (stream.match(identifiers)) {
141 return 'variable';
142 }
143
144 // Handle non-detected items
145 stream.next();
146 return ERRORCLASS;
147 }
148
149 function tokenStringFactory(delimiter) {
150 while ('rub'.indexOf(delimiter.charAt(0).toLowerCase()) >= 0) {
151 delimiter = delimiter.substr(1);
152 }
153 var singleline = delimiter.length == 1;
154 var OUTCLASS = 'string';
155
156 return function tokenString(stream, state) {
157 while (!stream.eol()) {
158 stream.eatWhile(/[^'"\\]/);
159 if (stream.eat('\\')) {
160 stream.next();
161 if (singleline && stream.eol()) {
162 return OUTCLASS;
163 }
164 } else if (stream.match(delimiter)) {
165 state.tokenize = tokenBase;
166 return OUTCLASS;
167 } else {
168 stream.eat(/['"]/);
169 }
170 }
171 if (singleline) {
172 if (parserConf.singleLineStringErrors) {
173 return ERRORCLASS;
174 } else {
175 state.tokenize = tokenBase;
176 }
177 }
178 return OUTCLASS;
179 };
180 }
181
182 function indent(stream, state, type) {
183 type = type || 'py';
184 var indentUnit = 0;
185 if (type === 'py') {
186 if (state.scopes[0].type !== 'py') {
187 state.scopes[0].offset = stream.indentation();
188 return;
189 }
190 for (var i = 0; i < state.scopes.length; ++i) {
191 if (state.scopes[i].type === 'py') {
192 indentUnit = state.scopes[i].offset + conf.indentUnit;
193 break;
194 }
195 }
196 } else {
197 indentUnit = stream.column() + stream.current().length;
198 }
199 state.scopes.unshift({
200 offset: indentUnit,
201 type: type
202 });
203 }
204
205 function dedent(stream, state, type) {
206 type = type || 'py';
207 if (state.scopes.length == 1) return;
208 if (state.scopes[0].type === 'py') {
209 var _indent = stream.indentation();
210 var _indent_index = -1;
211 for (var i = 0; i < state.scopes.length; ++i) {
212 if (_indent === state.scopes[i].offset) {
213 _indent_index = i;
214 break;
215 }
216 }
217 if (_indent_index === -1) {
218 return true;
219 }
220 while (state.scopes[0].offset !== _indent) {
221 state.scopes.shift();
222 }
223 return false
224 } else {
225 if (type === 'py') {
226 state.scopes[0].offset = stream.indentation();
227 return false;