| OLD | NEW |
| 1 // CodeMirror, copyright (c) by Marijn Haverbeke and others | 1 // CodeMirror, copyright (c) by Marijn Haverbeke and others |
| 2 // Distributed under an MIT license: http://codemirror.net/LICENSE | 2 // Distributed under an MIT license: http://codemirror.net/LICENSE |
| 3 | 3 |
| 4 (function(mod) { | 4 (function(mod) { |
| 5 if (typeof exports == "object" && typeof module == "object") // CommonJS | 5 if (typeof exports == "object" && typeof module == "object") // CommonJS |
| 6 mod(require("../../lib/codemirror")); | 6 mod(require("../../lib/codemirror")); |
| 7 else if (typeof define == "function" && define.amd) // AMD | 7 else if (typeof define == "function" && define.amd) // AMD |
| 8 define(["../../lib/codemirror"], mod); | 8 define(["../../lib/codemirror"], mod); |
| 9 else // Plain browser env | 9 else // Plain browser env |
| 10 mod(CodeMirror); | 10 mod(CodeMirror); |
| 11 })(function(CodeMirror) { | 11 })(function(CodeMirror) { |
| 12 "use strict"; | 12 "use strict"; |
| 13 | 13 |
| 14 function wordRegexp(words) { | 14 function wordRegexp(words) { |
| 15 return new RegExp("^((" + words.join(")|(") + "))\\b"); | 15 return new RegExp("^((" + words.join(")|(") + "))\\b"); |
| 16 } | 16 } |
| 17 | 17 |
| 18 var wordOperators = wordRegexp(["and", "or", "not", "is", "in"]); | 18 var wordOperators = wordRegexp(["and", "or", "not", "is"]); |
| 19 var commonKeywords = ["as", "assert", "break", "class", "continue", | 19 var commonKeywords = ["as", "assert", "break", "class", "continue", |
| 20 "def", "del", "elif", "else", "except", "finally", | 20 "def", "del", "elif", "else", "except", "finally", |
| 21 "for", "from", "global", "if", "import", | 21 "for", "from", "global", "if", "import", |
| 22 "lambda", "pass", "raise", "return", | 22 "lambda", "pass", "raise", "return", |
| 23 "try", "while", "with", "yield"]; | 23 "try", "while", "with", "yield", "in"]; |
| 24 var commonBuiltins = ["abs", "all", "any", "bin", "bool", "bytearray", "callab
le", "chr", | 24 var commonBuiltins = ["abs", "all", "any", "bin", "bool", "bytearray", "callab
le", "chr", |
| 25 "classmethod", "compile", "complex", "delattr", "dict",
"dir", "divmod", | 25 "classmethod", "compile", "complex", "delattr", "dict",
"dir", "divmod", |
| 26 "enumerate", "eval", "filter", "float", "format", "froze
nset", | 26 "enumerate", "eval", "filter", "float", "format", "froze
nset", |
| 27 "getattr", "globals", "hasattr", "hash", "help", "hex",
"id", | 27 "getattr", "globals", "hasattr", "hash", "help", "hex",
"id", |
| 28 "input", "int", "isinstance", "issubclass", "iter", "len
", | 28 "input", "int", "isinstance", "issubclass", "iter", "len
", |
| 29 "list", "locals", "map", "max", "memoryview", "min", "ne
xt", | 29 "list", "locals", "map", "max", "memoryview", "min", "ne
xt", |
| 30 "object", "oct", "open", "ord", "pow", "property", "rang
e", | 30 "object", "oct", "open", "ord", "pow", "property", "rang
e", |
| 31 "repr", "reversed", "round", "set", "setattr", "slice", | 31 "repr", "reversed", "round", "set", "setattr", "slice", |
| 32 "sorted", "staticmethod", "str", "sum", "super", "tuple"
, | 32 "sorted", "staticmethod", "str", "sum", "super", "tuple"
, |
| 33 "type", "vars", "zip", "__import__", "NotImplemented", | 33 "type", "vars", "zip", "__import__", "NotImplemented", |
| 34 "Ellipsis", "__debug__"]; | 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)); | 35 CodeMirror.registerHelper("hintWords", "python", commonKeywords.concat(commonB
uiltins)); |
| 43 | 36 |
| 44 function top(state) { | 37 function top(state) { |
| 45 return state.scopes[state.scopes.length - 1]; | 38 return state.scopes[state.scopes.length - 1]; |
| 46 } | 39 } |
| 47 | 40 |
| 48 CodeMirror.defineMode("python", function(conf, parserConf) { | 41 CodeMirror.defineMode("python", function(conf, parserConf) { |
| 49 var ERRORCLASS = "error"; | 42 var ERRORCLASS = "error"; |
| 50 | 43 |
| 51 var singleOperators = parserConf.singleOperators || new RegExp("^[\\+\\-\\*/
%&|\\^~<>!]"); | 44 var singleDelimiters = parserConf.singleDelimiters || /^[\(\)\[\]\{\}@,:`=;\
.]/; |
| 52 var singleDelimiters = parserConf.singleDelimiters || new RegExp("^[\\(\\)\\
[\\]\\{\\}@,:`=;\\.]"); | 45 var doubleOperators = parserConf.doubleOperators || /^([!<>]==|<>|<<|>>|\/\/
|\*\*)/; |
| 53 var doubleOperators = parserConf.doubleOperators || new RegExp("^((==)|(!=)|
(<=)|(>=)|(<>)|(<<)|(>>)|(//)|(\\*\\*))"); | 46 var doubleDelimiters = parserConf.doubleDelimiters || /^(\+=|\-=|\*=|%=|\/=|
&=|\|=|\^=)/; |
| 54 var doubleDelimiters = parserConf.doubleDelimiters || new RegExp("^((\\+=)|(
\\-=)|(\\*=)|(%=)|(/=)|(&=)|(\\|=)|(\\^=))"); | 47 var tripleDelimiters = parserConf.tripleDelimiters || /^(\/\/=|>>=|<<=|\*\*=
)/; |
| 55 var tripleDelimiters = parserConf.tripleDelimiters || new RegExp("^((//=)|(>
>=)|(<<=)|(\\*\\*=))"); | 48 |
| 56 var identifiers = parserConf.identifiers|| new RegExp("^[_A-Za-z][_A-Za-z0-9
]*"); | |
| 57 var hangingIndent = parserConf.hangingIndent || conf.indentUnit; | 49 var hangingIndent = parserConf.hangingIndent || conf.indentUnit; |
| 58 | 50 |
| 59 var myKeywords = commonKeywords, myBuiltins = commonBuiltins; | 51 var myKeywords = commonKeywords, myBuiltins = commonBuiltins; |
| 60 if(parserConf.extra_keywords != undefined){ | 52 if (parserConf.extra_keywords != undefined) |
| 61 myKeywords = myKeywords.concat(parserConf.extra_keywords); | 53 myKeywords = myKeywords.concat(parserConf.extra_keywords); |
| 62 } | 54 |
| 63 if(parserConf.extra_builtins != undefined){ | 55 if (parserConf.extra_builtins != undefined) |
| 64 myBuiltins = myBuiltins.concat(parserConf.extra_builtins); | 56 myBuiltins = myBuiltins.concat(parserConf.extra_builtins); |
| 65 } | 57 |
| 66 if (parserConf.version && parseInt(parserConf.version, 10) == 3) { | 58 var py3 = parserConf.version && parseInt(parserConf.version, 10) == 3 |
| 67 myKeywords = myKeywords.concat(py3.keywords); | 59 if (py3) { |
| 68 myBuiltins = myBuiltins.concat(py3.builtins); | 60 // since http://legacy.python.org/dev/peps/pep-0465/ @ is also an operator |
| 69 var stringPrefixes = new RegExp("^(([rb]|(br))?('{3}|\"{3}|['\"]))", "i"); | 61 var singleOperators = parserConf.singleOperators || /^[\+\-\*\/%&|\^~<>!@]
/; |
| 62 var identifiers = parserConf.identifiers|| /^[_A-Za-z\u00A1-\uFFFF][_A-Za-
z0-9\u00A1-\uFFFF]*/; |
| 63 myKeywords = myKeywords.concat(["nonlocal", "False", "True", "None", "asyn
c", "await"]); |
| 64 myBuiltins = myBuiltins.concat(["ascii", "bytes", "exec", "print"]); |
| 65 var stringPrefixes = new RegExp("^(([rbuf]|(br))?('{3}|\"{3}|['\"]))", "i"
); |
| 70 } else { | 66 } else { |
| 71 myKeywords = myKeywords.concat(py2.keywords); | 67 var singleOperators = parserConf.singleOperators || /^[\+\-\*\/%&|\^~<>!]/
; |
| 72 myBuiltins = myBuiltins.concat(py2.builtins); | 68 var identifiers = parserConf.identifiers|| /^[_A-Za-z][_A-Za-z0-9]*/; |
| 69 myKeywords = myKeywords.concat(["exec", "print"]); |
| 70 myBuiltins = myBuiltins.concat(["apply", "basestring", "buffer", "cmp", "c
oerce", "execfile", |
| 71 "file", "intern", "long", "raw_input", "re
duce", "reload", |
| 72 "unichr", "unicode", "xrange", "False", "T
rue", "None"]); |
| 73 var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))",
"i"); | 73 var stringPrefixes = new RegExp("^(([rub]|(ur)|(br))?('{3}|\"{3}|['\"]))",
"i"); |
| 74 } | 74 } |
| 75 var keywords = wordRegexp(myKeywords); | 75 var keywords = wordRegexp(myKeywords); |
| 76 var builtins = wordRegexp(myBuiltins); | 76 var builtins = wordRegexp(myBuiltins); |
| 77 | 77 |
| 78 // tokenizers | 78 // tokenizers |
| 79 function tokenBase(stream, state) { | 79 function tokenBase(stream, state) { |
| 80 if (stream.sol()) state.indent = stream.indentation() |
| 80 // Handle scope changes | 81 // Handle scope changes |
| 81 if (stream.sol() && top(state).type == "py") { | 82 if (stream.sol() && top(state).type == "py") { |
| 82 var scopeOffset = top(state).offset; | 83 var scopeOffset = top(state).offset; |
| 83 if (stream.eatSpace()) { | 84 if (stream.eatSpace()) { |
| 84 var lineOffset = stream.indentation(); | 85 var lineOffset = stream.indentation(); |
| 85 if (lineOffset > scopeOffset) | 86 if (lineOffset > scopeOffset) |
| 86 pushScope(stream, state, "py"); | 87 pushPyScope(state); |
| 87 else if (lineOffset < scopeOffset && dedent(stream, state)) | 88 else if (lineOffset < scopeOffset && dedent(stream, state)) |
| 88 state.errorToken = true; | 89 state.errorToken = true; |
| 89 return null; | 90 return null; |
| 90 } else { | 91 } else { |
| 91 var style = tokenBaseInner(stream, state); | 92 var style = tokenBaseInner(stream, state); |
| 92 if (scopeOffset > 0 && dedent(stream, state)) | 93 if (scopeOffset > 0 && dedent(stream, state)) |
| 93 style += " " + ERRORCLASS; | 94 style += " " + ERRORCLASS; |
| 94 return style; | 95 return style; |
| 95 } | 96 } |
| 96 } | 97 } |
| (...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 145 } | 146 } |
| 146 | 147 |
| 147 // Handle Strings | 148 // Handle Strings |
| 148 if (stream.match(stringPrefixes)) { | 149 if (stream.match(stringPrefixes)) { |
| 149 state.tokenize = tokenStringFactory(stream.current()); | 150 state.tokenize = tokenStringFactory(stream.current()); |
| 150 return state.tokenize(stream, state); | 151 return state.tokenize(stream, state); |
| 151 } | 152 } |
| 152 | 153 |
| 153 // Handle operators and Delimiters | 154 // Handle operators and Delimiters |
| 154 if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) | 155 if (stream.match(tripleDelimiters) || stream.match(doubleDelimiters)) |
| 155 return null; | 156 return "punctuation"; |
| 156 | 157 |
| 157 if (stream.match(doubleOperators) | 158 if (stream.match(doubleOperators) || stream.match(singleOperators)) |
| 158 || stream.match(singleOperators) | |
| 159 || stream.match(wordOperators)) | |
| 160 return "operator"; | 159 return "operator"; |
| 161 | 160 |
| 162 if (stream.match(singleDelimiters)) | 161 if (stream.match(singleDelimiters)) |
| 163 return null; | 162 return "punctuation"; |
| 164 | 163 |
| 165 if (stream.match(keywords)) | 164 if (state.lastToken == "." && stream.match(identifiers)) |
| 165 return "property"; |
| 166 |
| 167 if (stream.match(keywords) || stream.match(wordOperators)) |
| 166 return "keyword"; | 168 return "keyword"; |
| 167 | 169 |
| 168 if (stream.match(builtins)) | 170 if (stream.match(builtins)) |
| 169 return "builtin"; | 171 return "builtin"; |
| 170 | 172 |
| 171 if (stream.match(/^(self|cls)\b/)) | 173 if (stream.match(/^(self|cls)\b/)) |
| 172 return "variable-2"; | 174 return "variable-2"; |
| 173 | 175 |
| 174 if (stream.match(identifiers)) { | 176 if (stream.match(identifiers)) { |
| 175 if (state.lastToken == "def" || state.lastToken == "class") | 177 if (state.lastToken == "def" || state.lastToken == "class") |
| (...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 208 return ERRORCLASS; | 210 return ERRORCLASS; |
| 209 else | 211 else |
| 210 state.tokenize = tokenBase; | 212 state.tokenize = tokenBase; |
| 211 } | 213 } |
| 212 return OUTCLASS; | 214 return OUTCLASS; |
| 213 } | 215 } |
| 214 tokenString.isString = true; | 216 tokenString.isString = true; |
| 215 return tokenString; | 217 return tokenString; |
| 216 } | 218 } |
| 217 | 219 |
| 218 function pushScope(stream, state, type) { | 220 function pushPyScope(state) { |
| 219 var offset = 0, align = null; | 221 while (top(state).type != "py") state.scopes.pop() |
| 220 if (type == "py") { | 222 state.scopes.push({offset: top(state).offset + conf.indentUnit, |
| 221 while (top(state).type != "py") | 223 type: "py", |
| 222 state.scopes.pop(); | 224 align: null}) |
| 223 } | 225 } |
| 224 offset = top(state).offset + (type == "py" ? conf.indentUnit : hangingInde
nt); | 226 |
| 225 if (type != "py" && !stream.match(/^(\s|#.*)*$/, false)) | 227 function pushBracketScope(stream, state, type) { |
| 226 align = stream.column() + 1; | 228 var align = stream.match(/^([\s\[\{\(]|#.*)*$/, false) ? null : stream.col
umn() + 1 |
| 227 state.scopes.push({offset: offset, type: type, align: align}); | 229 state.scopes.push({offset: state.indent + hangingIndent, |
| 230 type: type, |
| 231 align: align}) |
| 228 } | 232 } |
| 229 | 233 |
| 230 function dedent(stream, state) { | 234 function dedent(stream, state) { |
| 231 var indented = stream.indentation(); | 235 var indented = stream.indentation(); |
| 232 while (top(state).offset > indented) { | 236 while (state.scopes.length > 1 && top(state).offset > indented) { |
| 233 if (top(state).type != "py") return true; | 237 if (top(state).type != "py") return true; |
| 234 state.scopes.pop(); | 238 state.scopes.pop(); |
| 235 } | 239 } |
| 236 return top(state).offset != indented; | 240 return top(state).offset != indented; |
| 237 } | 241 } |
| 238 | 242 |
| 239 function tokenLexer(stream, state) { | 243 function tokenLexer(stream, state) { |
| 244 if (stream.sol()) state.beginningOfLine = true; |
| 245 |
| 240 var style = state.tokenize(stream, state); | 246 var style = state.tokenize(stream, state); |
| 241 var current = stream.current(); | 247 var current = stream.current(); |
| 242 | 248 |
| 243 // Handle '.' connected identifiers | 249 // Handle decorators |
| 244 if (current == ".") { | 250 if (state.beginningOfLine && current == "@") |
| 245 style = stream.match(identifiers, false) ? null : ERRORCLASS; | 251 return stream.match(identifiers, false) ? "meta" : py3 ? "operator" : ER
RORCLASS; |
| 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 | 252 |
| 254 // Handle decorators | 253 if (/\S/.test(current)) state.beginningOfLine = false; |
| 255 if (current == "@") | |
| 256 return stream.match(identifiers, false) ? "meta" : ERRORCLASS; | |
| 257 | 254 |
| 258 if ((style == "variable" || style == "builtin") | 255 if ((style == "variable" || style == "builtin") |
| 259 && state.lastStyle == "meta") | 256 && state.lastToken == "meta") |
| 260 style = "meta"; | 257 style = "meta"; |
| 261 | 258 |
| 262 // Handle scope changes. | 259 // Handle scope changes. |
| 263 if (current == "pass" || current == "return") | 260 if (current == "pass" || current == "return") |
| 264 state.dedent += 1; | 261 state.dedent += 1; |
| 265 | 262 |
| 266 if (current == "lambda") state.lambda = true; | 263 if (current == "lambda") state.lambda = true; |
| 267 if (current == ":" && !state.lambda && top(state).type == "py") | 264 if (current == ":" && !state.lambda && top(state).type == "py") |
| 268 pushScope(stream, state, "py"); | 265 pushPyScope(state); |
| 269 | 266 |
| 270 var delimiter_index = current.length == 1 ? "[({".indexOf(current) : -1; | 267 var delimiter_index = current.length == 1 ? "[({".indexOf(current) : -1; |
| 271 if (delimiter_index != -1) | 268 if (delimiter_index != -1) |
| 272 pushScope(stream, state, "])}".slice(delimiter_index, delimiter_index+1)
); | 269 pushBracketScope(stream, state, "])}".slice(delimiter_index, delimiter_i
ndex+1)); |
| 273 | 270 |
| 274 delimiter_index = "])}".indexOf(current); | 271 delimiter_index = "])}".indexOf(current); |
| 275 if (delimiter_index != -1) { | 272 if (delimiter_index != -1) { |
| 276 if (top(state).type == current) state.scopes.pop(); | 273 if (top(state).type == current) state.indent = state.scopes.pop().offset
- hangingIndent |
| 277 else return ERRORCLASS; | 274 else return ERRORCLASS; |
| 278 } | 275 } |
| 279 if (state.dedent > 0 && stream.eol() && top(state).type == "py") { | 276 if (state.dedent > 0 && stream.eol() && top(state).type == "py") { |
| 280 if (state.scopes.length > 1) state.scopes.pop(); | 277 if (state.scopes.length > 1) state.scopes.pop(); |
| 281 state.dedent -= 1; | 278 state.dedent -= 1; |
| 282 } | 279 } |
| 283 | 280 |
| 284 return style; | 281 return style; |
| 285 } | 282 } |
| 286 | 283 |
| 287 var external = { | 284 var external = { |
| 288 startState: function(basecolumn) { | 285 startState: function(basecolumn) { |
| 289 return { | 286 return { |
| 290 tokenize: tokenBase, | 287 tokenize: tokenBase, |
| 291 scopes: [{offset: basecolumn || 0, type: "py", align: null}], | 288 scopes: [{offset: basecolumn || 0, type: "py", align: null}], |
| 292 lastStyle: null, | 289 indent: basecolumn || 0, |
| 293 lastToken: null, | 290 lastToken: null, |
| 294 lambda: false, | 291 lambda: false, |
| 295 dedent: 0 | 292 dedent: 0 |
| 296 }; | 293 }; |
| 297 }, | 294 }, |
| 298 | 295 |
| 299 token: function(stream, state) { | 296 token: function(stream, state) { |
| 300 var addErr = state.errorToken; | 297 var addErr = state.errorToken; |
| 301 if (addErr) state.errorToken = false; | 298 if (addErr) state.errorToken = false; |
| 302 var style = tokenLexer(stream, state); | 299 var style = tokenLexer(stream, state); |
| 303 | 300 |
| 304 state.lastStyle = style; | 301 if (style && style != "comment") |
| 305 | 302 state.lastToken = (style == "keyword" || style == "punctuation") ? str
eam.current() : style; |
| 306 var current = stream.current(); | 303 if (style == "punctuation") style = null; |
| 307 if (current && style) | |
| 308 state.lastToken = current; | |
| 309 | 304 |
| 310 if (stream.eol() && state.lambda) | 305 if (stream.eol() && state.lambda) |
| 311 state.lambda = false; | 306 state.lambda = false; |
| 312 return addErr ? style + " " + ERRORCLASS : style; | 307 return addErr ? style + " " + ERRORCLASS : style; |
| 313 }, | 308 }, |
| 314 | 309 |
| 315 indent: function(state, textAfter) { | 310 indent: function(state, textAfter) { |
| 316 if (state.tokenize != tokenBase) | 311 if (state.tokenize != tokenBase) |
| 317 return state.tokenize.isString ? CodeMirror.Pass : 0; | 312 return state.tokenize.isString ? CodeMirror.Pass : 0; |
| 318 | 313 |
| 319 var scope = top(state); | 314 var scope = top(state), closing = scope.type == textAfter.charAt(0) |
| 320 var closing = textAfter && textAfter.charAt(0) == scope.type; | |
| 321 if (scope.align != null) | 315 if (scope.align != null) |
| 322 return scope.align - (closing ? 1 : 0); | 316 return scope.align - (closing ? 1 : 0) |
| 323 else if (closing && state.scopes.length > 1) | |
| 324 return state.scopes[state.scopes.length - 2].offset; | |
| 325 else | 317 else |
| 326 return scope.offset; | 318 return scope.offset - (closing ? hangingIndent : 0) |
| 327 }, | 319 }, |
| 328 | 320 |
| 321 electricInput: /^\s*[\}\]\)]$/, |
| 322 closeBrackets: {triples: "'\""}, |
| 329 lineComment: "#", | 323 lineComment: "#", |
| 330 fold: "indent" | 324 fold: "indent" |
| 331 }; | 325 }; |
| 332 return external; | 326 return external; |
| 333 }); | 327 }); |
| 334 | 328 |
| 335 CodeMirror.defineMIME("text/x-python", "python"); | 329 CodeMirror.defineMIME("text/x-python", "python"); |
| 336 | 330 |
| 337 var words = function(str) { return str.split(" "); }; | 331 var words = function(str) { return str.split(" "); }; |
| 338 | 332 |
| 339 CodeMirror.defineMIME("text/x-cython", { | 333 CodeMirror.defineMIME("text/x-cython", { |
| 340 name: "python", | 334 name: "python", |
| 341 extra_keywords: words("by cdef cimport cpdef ctypedef enum except"+ | 335 extra_keywords: words("by cdef cimport cpdef ctypedef enum except"+ |
| 342 "extern gil include nogil property public"+ | 336 "extern gil include nogil property public"+ |
| 343 "readonly struct union DEF IF ELIF ELSE") | 337 "readonly struct union DEF IF ELIF ELSE") |
| 344 }); | 338 }); |
| 345 | 339 |
| 346 }); | 340 }); |
| OLD | NEW |