| 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 |