OLD | NEW |
1 CodeMirror.defineMode("python", function(conf, parserConf) { | 1 // CodeMirror, copyright (c) by Marijn Haverbeke and others |
2 var ERRORCLASS = 'error'; | 2 // Distributed under an MIT license: http://codemirror.net/LICENSE |
3 | 3 |
4 function wordRegexp(words) { | 4 (function(mod) { |
5 return new RegExp("^((" + words.join(")|(") + "))\\b"); | 5 if (typeof exports == "object" && typeof module == "object") // CommonJS |
6 } | 6 mod(require("../../lib/codemirror")); |
| 7 else if (typeof define == "function" && define.amd) // AMD |
| 8 define(["../../lib/codemirror"], mod); |
| 9 else // Plain browser env |
| 10 mod(CodeMirror); |
| 11 })(function(CodeMirror) { |
| 12 "use strict"; |
| 13 |
| 14 function wordRegexp(words) { |
| 15 return new RegExp("^((" + words.join(")|(") + "))\\b"); |
| 16 } |
| 17 |
| 18 var wordOperators = wordRegexp(["and", "or", "not", "is", "in"]); |
| 19 var commonKeywords = ["as", "assert", "break", "class", "continue", |
| 20 "def", "del", "elif", "else", "except", "finally", |
| 21 "for", "from", "global", "if", "import", |
| 22 "lambda", "pass", "raise", "return", |
| 23 "try", "while", "with", "yield"]; |
| 24 var commonBuiltins = ["abs", "all", "any", "bin", "bool", "bytearray", "callab
le", "chr", |
| 25 "classmethod", "compile", "complex", "delattr", "dict",
"dir", "divmod", |
| 26 "enumerate", "eval", "filter", "float", "format", "froze
nset", |
| 27 "getattr", "globals", "hasattr", "hash", "help", "hex",
"id", |
| 28 "input", "int", "isinstance", "issubclass", "iter", "len
", |
| 29 "list", "locals", "map", "max", "memoryview", "min", "ne
xt", |
| 30 "object", "oct", "open", "ord", "pow", "property", "rang
e", |
| 31 "repr", "reversed", "round", "set", "setattr", "slice", |
| 32 "sorted", "staticmethod", "str", "sum", "super", "tuple"
, |
| 33 "type", "vars", "zip", "__import__", "NotImplemented", |
| 34 "Ellipsis", "__debug__"]; |
| 35 var py2 = {builtins: ["apply", "basestring", "buffer", "cmp", "coerce", "execf
ile", |
| 36 "file", "intern", "long", "raw_input", "reduce", "reload
", |
| 37 "unichr", "unicode", "xrange", "False", "True", "None"], |
| 38 keywords: ["exec", "print"]}; |
| 39 var py3 = {builtins: ["ascii", "bytes", "exec", "print"], |
| 40 keywords: ["nonlocal", "False", "True", "None"]}; |
| 41 |
| 42 CodeMirror.registerHelper("hintWords", "python", commonKeywords.concat(commonB
uiltins)); |
| 43 |
| 44 function top(state) { |
| 45 return state.scopes[state.scopes.length - 1]; |
| 46 } |
| 47 |
| 48 CodeMirror.defineMode("python", function(conf, parserConf) { |
| 49 var ERRORCLASS = "error"; |
7 | 50 |
8 var singleOperators = parserConf.singleOperators || new RegExp("^[\\+\\-\\*/
%&|\\^~<>!]"); | 51 var singleOperators = parserConf.singleOperators || new RegExp("^[\\+\\-\\*/
%&|\\^~<>!]"); |
9 var singleDelimiters = parserConf.singleDelimiters || new RegExp('^[\\(\\)\\
[\\]\\{\\}@,:`=;\\.]'); | 52 var singleDelimiters = parserConf.singleDelimiters || new RegExp("^[\\(\\)\\
[\\]\\{\\}@,:`=;\\.]"); |
10 var doubleOperators = parserConf.doubleOperators || new RegExp("^((==)|(!=)|
(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))"); | 53 var doubleOperators = parserConf.doubleOperators || new RegExp("^((==)|(!=)|
(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))"); |
11 var doubleDelimiters = parserConf.doubleDelimiters || new RegExp("^((\\+=)|(
\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))"); | 54 var doubleDelimiters = parserConf.doubleDelimiters || new RegExp("^((\\+=)|(
\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))"); |
12 var tripleDelimiters = parserConf.tripleDelimiters || new RegExp("^((//=)|(>
>=)|(<<=)|(\\*\\*=))"); | 55 var tripleDelimiters = parserConf.tripleDelimiters || new RegExp("^((//=)|(>
>=)|(<<=)|(\\*\\*=))"); |
13 var identifiers = parserConf.identifiers|| new RegExp("^[_A-Za-z][_A-Za-z0-9
]*"); | 56 var identifiers = parserConf.identifiers|| new RegExp("^[_A-Za-z][_A-Za-z0-9
]*"); |
14 | 57 var hangingIndent = parserConf.hangingIndent || conf.indentUnit; |
15 var wordOperators = wordRegexp(['and', 'or', 'not', 'is', 'in']); | 58 |
16 var commonkeywords = ['as', 'assert', 'break', 'class', 'continue', | 59 var myKeywords = commonKeywords, myBuiltins = commonBuiltins; |
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 commonBuiltins = ['abs', 'all', 'any', 'bin', 'bool', 'bytearray', 'call
able', 'chr', | |
22 'classmethod', 'compile', 'complex', 'delattr', 'dict'
, 'dir', 'divmod', | |
23 'enumerate', 'eval', 'filter', 'float', 'format', 'fro
zenset', | |
24 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex'
, 'id', | |
25 'input', 'int', 'isinstance', 'issubclass', 'iter', 'l
en', | |
26 'list', 'locals', 'map', 'max', 'memoryview', 'min', '
next', | |
27 'object', 'oct', 'open', 'ord', 'pow', 'property', 'ra
nge', | |
28 'repr', 'reversed', 'round', 'set', 'setattr', 'slice'
, | |
29 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tupl
e', | |
30 'type', 'vars', 'zip', '__import__', 'NotImplemented', | |
31 'Ellipsis', '__debug__']; | |
32 var py2 = {'builtins': ['apply', 'basestring', 'buffer', 'cmp', 'coerce', 'e
xecfile', | |
33 'file', 'intern', 'long', 'raw_input', 'reduce', 're
load', | |
34 'unichr', 'unicode', 'xrange', 'False', 'True', 'Non
e'], | |
35 'keywords': ['exec', 'print']}; | |
36 var py3 = {'builtins': ['ascii', 'bytes', 'exec', 'print'], | |
37 'keywords': ['nonlocal', 'False', 'True', 'None']}; | |
38 | |
39 if(parserConf.extra_keywords != undefined){ | 60 if(parserConf.extra_keywords != undefined){ |
40 commonkeywords = commonkeywords.concat(parserConf.extra_keywords); | 61 myKeywords = myKeywords.concat(parserConf.extra_keywords); |
41 } | 62 } |
42 if(parserConf.extra_builtins != undefined){ | 63 if(parserConf.extra_builtins != undefined){ |
43 commonBuiltins = commonBuiltins.concat(parserConf.extra_builtins); | 64 myBuiltins = myBuiltins.concat(parserConf.extra_builtins); |
44 } | 65 } |
45 if (!!parserConf.version && parseInt(parserConf.version, 10) === 3) { | 66 if (parserConf.version && parseInt(parserConf.version, 10) == 3) { |
46 commonkeywords = commonkeywords.concat(py3.keywords); | 67 myKeywords = myKeywords.concat(py3.keywords); |
47 commonBuiltins = commonBuiltins.concat(py3.builtins); | 68 myBuiltins = myBuiltins.concat(py3.builtins); |
48 var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i"
); | 69 var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i"); |
49 } else { | 70 } else { |
50 commonkeywords = commonkeywords.concat(py2.keywords); | 71 myKeywords = myKeywords.concat(py2.keywords); |
51 commonBuiltins = commonBuiltins.concat(py2.builtins); | 72 myBuiltins = myBuiltins.concat(py2.builtins); |
52 var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))
", "i"); | 73 var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))",
"i"); |
53 } | 74 } |
54 var keywords = wordRegexp(commonkeywords); | 75 var keywords = wordRegexp(myKeywords); |
55 var builtins = wordRegexp(commonBuiltins); | 76 var builtins = wordRegexp(myBuiltins); |
56 | |
57 var indentInfo = null; | |
58 | 77 |
59 // tokenizers | 78 // tokenizers |
60 function tokenBase(stream, state) { | 79 function tokenBase(stream, state) { |
61 // Handle scope changes | 80 // Handle scope changes |
62 if (stream.sol()) { | 81 if (stream.sol() && top(state).type == "py") { |
63 var scopeOffset = state.scopes[0].offset; | 82 var scopeOffset = top(state).offset; |
64 if (stream.eatSpace()) { | |
65 var lineOffset = stream.indentation(); | |
66 if (lineOffset > scopeOffset) { | |
67 indentInfo = 'indent'; | |
68 } else if (lineOffset < scopeOffset) { | |
69 indentInfo = 'dedent'; | |
70 } | |
71 return null; | |
72 } else { | |
73 if (scopeOffset > 0) { | |
74 dedent(stream, state); | |
75 } | |
76 } | |
77 } | |
78 if (stream.eatSpace()) { | 83 if (stream.eatSpace()) { |
79 return null; | 84 var lineOffset = stream.indentation(); |
80 } | 85 if (lineOffset > scopeOffset) |
81 | 86 pushScope(stream, state, "py"); |
82 var ch = stream.peek(); | 87 else if (lineOffset < scopeOffset && dedent(stream, state)) |
83 | 88 state.errorToken = true; |
84 // Handle Comments | 89 return null; |
85 if (ch === '#') { | 90 } else { |
86 stream.skipToEnd(); | 91 var style = tokenBaseInner(stream, state); |
87 return 'comment'; | 92 if (scopeOffset > 0 && dedent(stream, state)) |
88 } | 93 style += " " + ERRORCLASS; |
89 | 94 return style; |
90 // Handle Number Literals | 95 } |
91 if (stream.match(/^[0-9\.]/, false)) { | 96 } |
92 var floatLiteral = false; | 97 return tokenBaseInner(stream, state); |
93 // Floats | 98 } |
94 if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true;
} | 99 |
95 if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; } | 100 function tokenBaseInner(stream, state) { |
96 if (stream.match(/^\.\d+/)) { floatLiteral = true; } | 101 if (stream.eatSpace()) return null; |
97 if (floatLiteral) { | 102 |
98 // Float literals may be "imaginary" | 103 var ch = stream.peek(); |
99 stream.eat(/J/i); | 104 |
100 return 'number'; | 105 // Handle Comments |
101 } | 106 if (ch == "#") { |
102 // Integers | 107 stream.skipToEnd(); |
103 var intLiteral = false; | 108 return "comment"; |
104 // Hex | 109 } |
105 if (stream.match(/^0x[0-9a-f]+/i)) { intLiteral = true; } | 110 |
106 // Binary | 111 // Handle Number Literals |
107 if (stream.match(/^0b[01]+/i)) { intLiteral = true; } | 112 if (stream.match(/^[0-9\.]/, false)) { |
108 // Octal | 113 var floatLiteral = false; |
109 if (stream.match(/^0o[0-7]+/i)) { intLiteral = true; } | 114 // Floats |
110 // Decimal | 115 if (stream.match(/^\d*\.\d+(e[\+\-]?\d+)?/i)) { floatLiteral = true; } |
111 if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) { | 116 if (stream.match(/^\d+\.\d*/)) { floatLiteral = true; } |
112 // Decimal literals may be "imaginary" | 117 if (stream.match(/^\.\d+/)) { floatLiteral = true; } |
113 stream.eat(/J/i); | 118 if (floatLiteral) { |
114 // TODO - Can you have imaginary longs? | 119 // Float literals may be "imaginary" |
115 intLiteral = true; | 120 stream.eat(/J/i); |
116 } | 121 return "number"; |
117 // Zero by itself with no other piece of number. | 122 } |
118 if (stream.match(/^0(?![\dx])/i)) { intLiteral = true; } | 123 // Integers |
119 if (intLiteral) { | 124 var intLiteral = false; |
120 // Integer literals may be "long" | 125 // Hex |
121 stream.eat(/L/i); | 126 if (stream.match(/^0x[0-9a-f]+/i)) intLiteral = true; |
122 return 'number'; | 127 // Binary |
123 } | 128 if (stream.match(/^0b[01]+/i)) intLiteral = true; |
124 } | 129 // Octal |
125 | 130 if (stream.match(/^0o[0-7]+/i)) intLiteral = true; |
126 // Handle Strings | 131 // Decimal |
127 if (stream.match(stringPrefixes)) { | 132 if (stream.match(/^[1-9]\d*(e[\+\-]?\d+)?/)) { |
128 state.tokenize = tokenStringFactory(stream.current()); | 133 // Decimal literals may be "imaginary" |
129 return state.tokenize(stream, state); | 134 stream.eat(/J/i); |
130 } | 135 // TODO - Can you have imaginary longs? |
131 | 136 intLiteral = true; |
132 // Handle operators and Delimiters | 137 } |
133 if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) { | 138 // Zero by itself with no other piece of number. |
134 return null; | 139 if (stream.match(/^0(?![\dx])/i)) intLiteral = true; |
135 } | 140 if (intLiteral) { |
136 if (stream.match(doubleOperators) | 141 // Integer literals may be "long" |
137 || stream.match(singleOperators) | 142 stream.eat(/L/i); |
138 || stream.match(wordOperators)) { | 143 return "number"; |
139 return 'operator'; | 144 } |
140 } | 145 } |
141 if (stream.match(singleDelimiters)) { | 146 |
142 return null; | 147 // Handle Strings |
143 } | 148 if (stream.match(stringPrefixes)) { |
144 | 149 state.tokenize = tokenStringFactory(stream.current()); |
145 if (stream.match(keywords)) { | 150 return state.tokenize(stream, state); |
146 return 'keyword'; | 151 } |
147 } | 152 |
148 | 153 // Handle operators and Delimiters |
149 if (stream.match(builtins)) { | 154 if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) |
150 return 'builtin'; | 155 return null; |
151 } | 156 |
152 | 157 if (stream.match(doubleOperators) |
153 if (stream.match(identifiers)) { | 158 || stream.match(singleOperators) |
154 if (state.lastToken == 'def' || state.lastToken == 'class') { | 159 || stream.match(wordOperators)) |
155 return 'def'; | 160 return "operator"; |
156 } | 161 |
157 return 'variable'; | 162 if (stream.match(singleDelimiters)) |
158 } | 163 return null; |
159 | 164 |
160 // Handle non-detected items | 165 if (stream.match(keywords)) |
161 stream.next(); | 166 return "keyword"; |
162 return ERRORCLASS; | 167 |
| 168 if (stream.match(builtins)) |
| 169 return "builtin"; |
| 170 |
| 171 if (stream.match(/^(self|cls)\b/)) |
| 172 return "variable-2"; |
| 173 |
| 174 if (stream.match(identifiers)) { |
| 175 if (state.lastToken == "def" || state.lastToken == "class") |
| 176 return "def"; |
| 177 return "variable"; |
| 178 } |
| 179 |
| 180 // Handle non-detected items |
| 181 stream.next(); |
| 182 return ERRORCLASS; |
163 } | 183 } |
164 | 184 |
165 function tokenStringFactory(delimiter) { | 185 function tokenStringFactory(delimiter) { |
166 while ('rub'.indexOf(delimiter.charAt(0).toLowerCase()) >= 0) { | 186 while ("rub".indexOf(delimiter.charAt(0).toLowerCase()) >= 0) |
167 delimiter = delimiter.substr(1); | 187 delimiter = delimiter.substr(1); |
168 } | 188 |
169 var singleline = delimiter.length == 1; | 189 var singleline = delimiter.length == 1; |
170 var OUTCLASS = 'string'; | 190 var OUTCLASS = "string"; |
171 | 191 |
172 function tokenString(stream, state) { | 192 function tokenString(stream, state) { |
173 while (!stream.eol()) { | 193 while (!stream.eol()) { |
174 stream.eatWhile(/[^'"\\]/); | 194 stream.eatWhile(/[^'"\\]/); |
175 if (stream.eat('\\')) { | 195 if (stream.eat("\\")) { |
176 stream.next(); | 196 stream.next(); |
177 if (singleline && stream.eol()) { | 197 if (singleline && stream.eol()) |
178 return OUTCLASS; | 198 return OUTCLASS; |
179 } | 199 } else if (stream.match(delimiter)) { |
180 } else if (stream.match(delimiter)) { | 200 state.tokenize = tokenBase; |
181 state.tokenize = tokenBase; | |
182 return OUTCLASS; | |
183 } else { | |
184 stream.eat(/['"]/); | |
185 } | |
186 } | |
187 if (singleline) { | |
188 if (parserConf.singleLineStringErrors) { | |
189 return ERRORCLASS; | |
190 } else { | |
191 state.tokenize = tokenBase; | |
192 } | |
193 } | |
194 return OUTCLASS; | 201 return OUTCLASS; |
195 } | 202 } else { |
196 tokenString.isString = true; | 203 stream.eat(/['"]/); |
197 return tokenString; | 204 } |
198 } | 205 } |
199 | 206 if (singleline) { |
200 function indent(stream, state, type) { | 207 if (parserConf.singleLineStringErrors) |
201 type = type || 'py'; | 208 return ERRORCLASS; |
202 var indentUnit = 0; | 209 else |
203 if (type === 'py') { | 210 state.tokenize = tokenBase; |
204 if (state.scopes[0].type !== 'py') { | 211 } |
205 state.scopes[0].offset = stream.indentation(); | 212 return OUTCLASS; |
206 return; | 213 } |
207 } | 214 tokenString.isString = true; |
208 for (var i = 0; i < state.scopes.length; ++i) { | 215 return tokenString; |
209 if (state.scopes[i].type === 'py') { | 216 } |
210 indentUnit = state.scopes[i].offset + conf.indentUnit; | 217 |
211 break; | 218 function pushScope(stream, state, type) { |
212 } | 219 var offset = 0, align = null; |
213 } | 220 if (type == "py") { |
214 } else { | 221 while (top(state).type != "py") |
215 indentUnit = stream.column() + stream.current().length; | 222 state.scopes.pop(); |
216 } | 223 } |
217 state.scopes.unshift({ | 224 offset = top(state).offset + (type == "py" ? conf.indentUnit : hangingInde
nt); |
218 offset: indentUnit, | 225 if (type != "py" && !stream.match(/^(\s|#.*)*$/, false)) |
219 type: type | 226 align = stream.column() + 1; |
220 }); | 227 state.scopes.push({offset: offset, type: type, align: align}); |
221 } | 228 } |
222 | 229 |
223 function dedent(stream, state, type) { | 230 function dedent(stream, state) { |
224 type = type || 'py'; | 231 var indented = stream.indentation(); |
225 if (state.scopes.length == 1) return; | 232 while (top(state).offset > indented) { |
226 if (state.scopes[0].type === 'py') { | 233 if (top(state).type != "py") return true; |
227 var _indent = stream.indentation(); | 234 state.scopes.pop(); |
228 var _indent_index = -1; | 235 } |
229 for (var i = 0; i < state.scopes.length; ++i) { | 236 return top(state).offset != indented; |
230 if (_indent === state.scopes[i].offset) { | |
231 _indent_index = i; | |
232 break; | |
233 } | |
234 } | |
235 if (_indent_index === -1) { | |
236 return true; | |
237 } | |
238 while (state.scopes[0].offset !== _indent) { | |
239 state.scopes.shift(); | |
240 } | |
241 return false; | |
242 } else { | |
243 if (type === 'py') { | |
244 state.scopes[0].offset = stream.indentation(); | |
245 return false; | |
246 } else { | |
247 if (state.scopes[0].type != type) { | |
248 return true; | |
249 } | |
250 state.scopes.shift(); | |
251 return false; | |
252 } | |
253 } | |
254 } | 237 } |
255 | 238 |
256 function tokenLexer(stream, state) { | 239 function tokenLexer(stream, state) { |
257 indentInfo = null; | 240 var style = state.tokenize(stream, state); |
258 var style = state.tokenize(stream, state); | 241 var current = stream.current(); |
| 242 |
| 243 // Handle '.' connected identifiers |
| 244 if (current == ".") { |
| 245 style = stream.match(identifiers, false) ? null : ERRORCLASS; |
| 246 if (style == null && state.lastStyle == "meta") { |
| 247 // Apply 'meta' style to '.' connected identifiers when |
| 248 // appropriate. |
| 249 style = "meta"; |
| 250 } |
| 251 return style; |
| 252 } |
| 253 |
| 254 // Handle decorators |
| 255 if (current == "@") |
| 256 return stream.match(identifiers, false) ? "meta" : ERRORCLASS; |
| 257 |
| 258 if ((style == "variable" || style == "builtin") |
| 259 && state.lastStyle == "meta") |
| 260 style = "meta"; |
| 261 |
| 262 // Handle scope changes. |
| 263 if (current == "pass" || current == "return") |
| 264 state.dedent += 1; |
| 265 |
| 266 if (current == "lambda") state.lambda = true; |
| 267 if (current == ":" && !state.lambda && top(state).type == "py") |
| 268 pushScope(stream, state, "py"); |
| 269 |
| 270 var delimiter_index = current.length == 1 ? "[({".indexOf(current) : -1; |
| 271 if (delimiter_index != -1) |
| 272 pushScope(stream, state, "])}".slice(delimiter_index, delimiter_index+1)
); |
| 273 |
| 274 delimiter_index = "])}".indexOf(current); |
| 275 if (delimiter_index != -1) { |
| 276 if (top(state).type == current) state.scopes.pop(); |
| 277 else return ERRORCLASS; |
| 278 } |
| 279 if (state.dedent > 0 && stream.eol() && top(state).type == "py") { |
| 280 if (state.scopes.length > 1) state.scopes.pop(); |
| 281 state.dedent -= 1; |
| 282 } |
| 283 |
| 284 return style; |
| 285 } |
| 286 |
| 287 var external = { |
| 288 startState: function(basecolumn) { |
| 289 return { |
| 290 tokenize: tokenBase, |
| 291 scopes: [{offset: basecolumn || 0, type: "py", align: null}], |
| 292 lastStyle: null, |
| 293 lastToken: null, |
| 294 lambda: false, |
| 295 dedent: 0 |
| 296 }; |
| 297 }, |
| 298 |
| 299 token: function(stream, state) { |
| 300 var addErr = state.errorToken; |
| 301 if (addErr) state.errorToken = false; |
| 302 var style = tokenLexer(stream, state); |
| 303 |
| 304 state.lastStyle = style; |
| 305 |
259 var current = stream.current(); | 306 var current = stream.current(); |
260 | 307 if (current && style) |
261 // Handle '.' connected identifiers | 308 state.lastToken = current; |
262 if (current === '.') { | 309 |
263 style = stream.match(identifiers, false) ? null : ERRORCLASS; | 310 if (stream.eol() && state.lambda) |
264 if (style === null && state.lastStyle === 'meta') { | 311 state.lambda = false; |
265 // Apply 'meta' style to '.' connected identifiers when | 312 return addErr ? style + " " + ERRORCLASS : style; |
266 // appropriate. | 313 }, |
267 style = 'meta'; | 314 |
268 } | 315 indent: function(state, textAfter) { |
269 return style; | 316 if (state.tokenize != tokenBase) |
270 } | 317 return state.tokenize.isString ? CodeMirror.Pass : 0; |
271 | 318 |
272 // Handle decorators | 319 var scope = top(state); |
273 if (current === '@') { | 320 var closing = textAfter && textAfter.charAt(0) == scope.type; |
274 return stream.match(identifiers, false) ? 'meta' : ERRORCLASS; | 321 if (scope.align != null) |
275 } | 322 return scope.align - (closing ? 1 : 0); |
276 | 323 else if (closing && state.scopes.length > 1) |
277 if ((style === 'variable' || style === 'builtin') | 324 return state.scopes[state.scopes.length - 2].offset; |
278 && state.lastStyle === 'meta') { | 325 else |
279 style = 'meta'; | 326 return scope.offset; |
280 } | 327 }, |
281 | 328 |
282 // Handle scope changes. | 329 lineComment: "#", |
283 if (current === 'pass' || current === 'return') { | 330 fold: "indent" |
284 state.dedent += 1; | |
285 } | |
286 if (current === 'lambda') state.lambda = true; | |
287 if ((current === ':' && !state.lambda && state.scopes[0].type == 'py') | |
288 || indentInfo === 'indent') { | |
289 indent(stream, state); | |
290 } | |
291 var delimiter_index = '[({'.indexOf(current); | |
292 if (delimiter_index !== -1) { | |
293 indent(stream, state, '])}'.slice(delimiter_index, delimiter_index+1
)); | |
294 } | |
295 if (indentInfo === 'dedent') { | |
296 if (dedent(stream, state)) { | |
297 return ERRORCLASS; | |
298 } | |
299 } | |
300 delimiter_index = '])}'.indexOf(current); | |
301 if (delimiter_index !== -1) { | |
302 if (dedent(stream, state, current)) { | |
303 return ERRORCLASS; | |
304 } | |
305 } | |
306 if (state.dedent > 0 && stream.eol() && state.scopes[0].type == 'py') { | |
307 if (state.scopes.length > 1) state.scopes.shift(); | |
308 state.dedent -= 1; | |
309 } | |
310 | |
311 return style; | |
312 } | |
313 | |
314 var external = { | |
315 startState: function(basecolumn) { | |
316 return { | |
317 tokenize: tokenBase, | |
318 scopes: [{offset:basecolumn || 0, type:'py'}], | |
319 lastStyle: null, | |
320 lastToken: null, | |
321 lambda: false, | |
322 dedent: 0 | |
323 }; | |
324 }, | |
325 | |
326 token: function(stream, state) { | |
327 var style = tokenLexer(stream, state); | |
328 | |
329 state.lastStyle = style; | |
330 | |
331 var current = stream.current(); | |
332 if (current && style) { | |
333 state.lastToken = current; | |
334 } | |
335 | |
336 if (stream.eol() && state.lambda) { | |
337 state.lambda = false; | |
338 } | |
339 return style; | |
340 }, | |
341 | |
342 indent: function(state) { | |
343 if (state.tokenize != tokenBase) { | |
344 return state.tokenize.isString ? CodeMirror.Pass : 0; | |
345 } | |
346 | |
347 return state.scopes[0].offset; | |
348 }, | |
349 | |
350 lineComment: "#", | |
351 fold: "indent" | |
352 }; | 331 }; |
353 return external; | 332 return external; |
354 }); | 333 }); |
355 | 334 |
356 CodeMirror.defineMIME("text/x-python", "python"); | 335 CodeMirror.defineMIME("text/x-python", "python"); |
357 | 336 |
358 (function() { | 337 var words = function(str) { return str.split(" "); }; |
359 "use strict"; | |
360 var words = function(str){return str.split(' ');}; | |
361 | 338 |
362 CodeMirror.defineMIME("text/x-cython", { | 339 CodeMirror.defineMIME("text/x-cython", { |
363 name: "python", | 340 name: "python", |
364 extra_keywords: words("by cdef cimport cpdef ctypedef enum except"+ | 341 extra_keywords: words("by cdef cimport cpdef ctypedef enum except"+ |
365 "extern gil include nogil property public"+ | 342 "extern gil include nogil property public"+ |
366 "readonly struct union DEF IF ELIF ELSE") | 343 "readonly struct union DEF IF ELIF ELSE") |
367 }); | 344 }); |
368 })(); | 345 |
| 346 }); |
OLD | NEW |